zl程序教程

您现在的位置是:首页 >  Java

当前栏目

【翻译】Spring Security抛弃了WebSecurityConfigurerAdapter

2023-03-31 11:05:20 时间

原文链接: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,我们引入EmbeddedLdapServerContextSourceFactoryBeanLdapBindAuthenticationManagerFactoryLdapPasswordComparisonAuthenticationManagerFactory,这些类都可以用来创建一个嵌入式的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上找到我们。