【翻译】Spring Security抛弃了WebSecurityConfigurerAdapter
原文链接:Spring Security without the WebSecurityConfigurerAdapter
作者:ELEFTHERIA STEIN-KOUSATHANA
发表日期:2022年2月21日
在Spring Security 5.7.0-M2,我们弃用了WebSecurityConfigurerAdapter
,因为我们鼓励用户转向使用基于组件的安全配置。
为了帮助大家熟悉这种新的配置风格,我们编制了一份常见用例表和推荐的新写法。
在下面的例子中,我们遵循最佳实践——使用Spring Security lambda领域专用语言(DSL)和HttpSecurity#authorizeHttpRequests
方法来定义我们的授权规则。如果你对lambda领域专用语言(DSL)不熟悉,你可以在这篇博客了解它。如果你想知道为什么我们选择选择使用HttpSecurity#authorizeHttpRequests
,你可以看这篇参考文档。
配置HttpSecurity
在Spring Security 5.4,我们引入了创建一个SecurityFilterChian
bean来配置HttpSecurity
的功能。
下面是一个使用WebSecurityConfigurerAdapter
和HTTP Basic保护所有端点的示例配置:
1 @Configuration 2 public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 3 4 @Override 5 protected void configure(HttpSecurity http) throws Exception { 6 http 7 .authorizeHttpRequests((authz) -> authz 8 .anyRequest().authenticated() 9 ) 10 .httpBasic(withDefaults()); 11 } 12 13 }
往后,我们建议注册一个SecurityFilterChain
bean来做这件事:
1 @Configuration 2 public class SecurityConfiguration { 3 4 @Bean 5 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 6 http 7 .authorizeHttpRequests((authz) -> authz 8 .anyRequest().authenticated() 9 ) 10 .httpBasic(withDefaults()); 11 return http.build(); 12 } 13 14 }
配置WebSecurity
在Spring Security 5.4中,我们还引入了WebSecurityCustomizer
。
WebSecurityCustomizer
是一个回调接口,可以用来定制WebSecurity
。
下面是一个使用WebSecurityConfigurerAdapter
忽略匹配/ignore1
或/ignore2
的请求的示例配置:
1 @Configuration 2 public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 3 4 @Override 5 public void configure(WebSecurity web) { 6 web.ignoring().antMatchers("/ignore1", "/ignore2"); 7 } 8 9 }
往后,我们建议注册一个WebSecurityCustomizer
bean来做这件事:
1 @Configuration 2 public class SecurityConfiguration { 3 4 @Bean 5 public WebSecurityCustomizer webSecurityCustomizer() { 6 return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2"); 7 } 8 9 }
警告:如果你正在配置WebSecurity
来忽略请求,建议你改为在HttpSecurity#authorizeHttpRequests内使用permitAll
。想了解更多请参考configure
Javadoc。
LDAP认证
在Spring Security 5.7,我们引入了EmbeddedLdapServerContextSourceFactoryBean
、LdapBindAuthenticationManagerFactory
和LdapPasswordComparisonAuthenticationManagerFactory
,这些类都可以用来创建一个嵌入式的LDAP服务器;并且我们还引入一个AuthenticationManager
类,它可以用来执行LDAP认证。
下面是一个使用是一个使用绑定验证的示例配置,它使用了WebSecurityConfugurerAdapter
创建嵌入式LDAP服务器并且使用AuthenticationManager
执行LDAP认证(Below is an example configuration using WebSecurityConfigurerAdappter
the that creates an embedded LDAP server and an AuthenticationManager
that performs LDAP authentication using bingd authentication):
1 @Configuration 2 public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 3 4 @Override 5 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 6 auth 7 .ldapAuthentication() 8 .userDetailsContextMapper(new PersonContextMapper()) 9 .userDnPatterns("uid={0},ou=people") 10 .contextSource() 11 .port(0); 12 } 13 14 }
往后,我们建议使用新的LDAP类来做这件事:
1 @Configuration 2 public class SecurityConfiguration { 3 @Bean 4 public EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() { 5 EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean = 6 EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer(); 7 contextSourceFactoryBean.setPort(0); 8 return contextSourceFactoryBean; 9 } 10 11 @Bean 12 AuthenticationManager ldapAuthenticationManager( 13 BaseLdapPathContextSource contextSource) { 14 LdapBindAuthenticationManagerFactory factory = 15 new LdapBindAuthenticationManagerFactory(contextSource); 16 factory.setUserDnPatterns("uid={0},ou=people"); 17 factory.setUserDetailsContextMapper(new PersonContextMapper()); 18 return factory.createAuthenticationManager(); 19 } 20 }
JDBC认证
下面是一个示例配置,它在WebSecurityConfigurerAdapter
内创建了一个使用默认模式初始化并且只有一个用户的内嵌DataSource
:
1 @Configuration 2 public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 3 @Bean 4 public DataSource dataSource() { 5 return new EmbeddedDatabaseBuilder() 6 .setType(EmbeddedDatabaseType.H2) 7 .build(); 8 } 9 10 @Override 11 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 12 UserDetails user = User.withDefaultPasswordEncoder() 13 .username("user") 14 .password("password") 15 .roles("USER") 16 .build(); 17 auth.jdbcAuthentication() 18 .withDefaultSchema() 19 .dataSource(dataSource()) 20 .withUser(user); 21 } 22 }
推荐的做法是创建一个JdbcUserDetailsManager
bean来做这件事:
1 @Configuration 2 public class SecurityConfiguration { 3 @Bean 4 public DataSource dataSource() { 5 return new EmbeddedDatabaseBuilder() 6 .setType(EmbeddedDatabaseType.H2) 7 .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION) 8 .build(); 9 } 10 11 @Bean 12 public UserDetailsManager users(DataSource dataSource) { 13 UserDetails user = User.withDefaultPasswordEncoder() 14 .username("user") 15 .password("password") 16 .roles("USER") 17 .build(); 18 JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource); 19 users.createUser(user); 20 return users; 21 } 22 }
注意:在这些例子中,我们为了可读性使用了User.withDefaultPasswrdEncoder()
。这不适合生产项目,我们建议在生产项目中使用散列密码。请按照参考文档所说的用Spring Boot命令行工具来做。
内存内认证
下面是一个示例配置,它在WebSecurityConfugurerAdapter
配置了一个只存有一个用户的内存内用户:
1 @Configuration 2 public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 3 @Override 4 protected void configure(AuthenticationManagerBuilder auth) throws Exception { 5 UserDetails user = User.withDefaultPasswordEncoder() 6 .username("user") 7 .password("password") 8 .roles("USER") 9 .build(); 10 auth.inMemoryAuthentication() 11 .withUser(user); 12 } 13 }
我们建议注册一个InMemoryUserDetailsManager
bean来做这件事:
1 @Configuration 2 public class SecurityConfiguration { 3 @Bean 4 public InMemoryUserDetailsManager userDetailsService() { 5 UserDetails user = User.withDefaultPasswordEncoder() 6 .username("user") 7 .password("password") 8 .roles("USER") 9 .build(); 10 return new InMemoryUserDetailsManager(user); 11 } 12 }
注意:在这些例子中,我们为了可读性使用了User.withDefaultPasswrdEncoder()
。这不适合生产项目,我们建议在生产项目中使用散列密码。请按照参考文档所说的用Spring Boot命令行工具来做。
全局AuthenticationManager
要创建一个整个应用都可以使用的AuthenticationManager
,只需要使用@Bean将AuthenticationManager
注册为bean就可以了。
这种配置已经在上面的LDAP认证示例展示过了。
局部AuthenticationManager
在Spring Security 5.6中,我们引入了HttpSecurity#authenticationManager方法,这个方法可以为特定的SecurityFilterChain
覆盖默认的AuthenticationManager
。
下面是一个示例配置,它设置了一个自定义的AuthenticationManager
:
1 @Configuration 2 public class SecurityConfiguration { 3 4 @Bean 5 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 6 http 7 .authorizeHttpRequests((authz) -> authz 8 .anyRequest().authenticated() 9 ) 10 .httpBasic(withDefaults()) 11 .authenticationManager(new CustomAuthenticationManager()); 12 return http.build(); 13 } 14 15 }
访问局部AuthenticationManager
可以使用自定义领域专用语言(DSL)访问局部AuthenticationManager
。这实际上是Spring Security内部实现HttpSecurity.authorizeRequests()
等方法的方式。
1 public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> { 2 @Override 3 public void configure(HttpSecurity http) throws Exception { 4 AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); 5 http.addFilter(new CustomFilter(authenticationManager)); 6 } 7 8 public static MyCustomDsl customDsl() { 9 return new MyCustomDsl(); 10 } 11 }
然后,在构建SecurityFilterchain
时可以应用自定义领域专用语言(DSL):
1 @Bean 2 public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 3 // ... 4 http.apply(customDsl()); 5 return http.build(); 6 }
欢迎加入
我们很高兴与您分享这些更新,我们期待通过您的反馈进一步增强Spring安全性!如果你有兴趣贡献,你可以在GitHub上找到我们。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)