没有WebSecurityConfigurerAdapter的Spring Security

Kwoky 2024-07-30 14:03:01 阅读 98

没有WebSecurityConfigurerAdapter的Spring Security

最近一直在从springboot2.x向3.x学习迁移,付出了很大的学习成本,心得会不断分享。对于spring security来说,是该和WebSecurityConfigurerAdapter说再见了,因为在Spring Security 5.7.0-M2中WebSecurityConfigurerAdapter已经被弃用找不到了。搬来了官方的博文,翻译不好的地方可以看原文,链接如下:

Spring Security without the WebSecurityConfigurerAdapter

在Spring Security 5.7.0-M2中,我们弃用了WebSecurityConfigurerAdapter,因为我们鼓励用户转向基于组件的安全配置。

为了帮助过渡到这种新的配置风格,我们编制了一份常见用例和建议替代方案的列表。

在下面的示例中,我们遵循最佳实践,使用Spring Security lambda DSL和方法httpsecurity# authorizeHttpRequests来定义授权规则。如果您是lambda DSL的新手,您可以在这篇博客文章中了解它。如果你想了解更多关于为什么我们选择使用httpsecurity# authorizeHttpRequests,你可以查看参考文档(Authorize HttpServletRequests :: Spring Security)。

配置HttpSecurity

在Spring Security 5.4中,我们引入了通过创建SecurityFilterChain bean来配置HttpSecurity的功能。

下面是一个使用WebSecurityConfigurerAdapter的配置示例,它使用HTTP Basic保护所有端点:

@Configuration

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override

    protected void configure(HttpSecurity http) throws Exception {

        http

            .authorizeHttpRequests((authz) -> authz

                .anyRequest().authenticated()

            )

            .httpBasic(withDefaults());

    }

}

接下来,推荐的方法是注册一个SecurityFilterChain bean:

@Configuration

public class SecurityConfiguration {

    @Bean

    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http

            .authorizeHttpRequests((authz) -> authz

                .anyRequest().authenticated()

            )

            .httpBasic(withDefaults());

        return http.build();

    }

}

配置WebSecurity

在Spring Security 5.4中,我们还引入了WebSecurityCustomizer。

WebSecurityCustomizer是一个回调接口,可用于自定义WebSecurity。

下面是一个使用WebSecurityConfigurerAdapter忽略匹配/ignore1或/ignore2的请求的配置示例:

@Configuration

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override

    public void configure(WebSecurity web) {

        web.ignoring().antMatchers("/ignore1", "/ignore2");

    }

}

接下来,推荐的方法是注册一个WebSecurityCustomizer bean:

@Configuration

public class SecurityConfiguration {

    @Bean

    public WebSecurityCustomizer webSecurityCustomizer() {

        return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");

    }

}

警告:如果你将WebSecurity配置为忽略请求,请考虑通过httpsecurity# authorizeHttpRequests使用permitAll。有关其他详细信息,请参阅configure Javadoc。

LDAP身份验证

在Spring Security 5.7中,我们介绍了EmbeddedLdapServerContextSourceFactoryBean、LdapBindAuthenticationManagerFactory和LdapPasswordComparisonAuthenticationManagerFactory,它们可用于创建嵌入式LDAP服务器和执行LDAP身份验证的AuthenticationManager。

下面是一个使用WebSecurityConfigurerAdapter的配置示例,它创建了一个嵌入式LDAP服务器和一个使用绑定身份验证执行LDAP身份验证的AuthenticationManager:

@Configuration

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth

            .ldapAuthentication()

            .userDetailsContextMapper(new PersonContextMapper())

            .userDnPatterns("uid={0},ou=people")

            .contextSource()

            .port(0);

    }

}

接下来,推荐的方法是使用新的LDAP类:

@Configuration

public class SecurityConfiguration {

    @Bean

    public EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {

        EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean =

            EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer();

        contextSourceFactoryBean.setPort(0);

        return contextSourceFactoryBean;

    }

    @Bean

    AuthenticationManager ldapAuthenticationManager(

            BaseLdapPathContextSource contextSource) {

        LdapBindAuthenticationManagerFactory factory =

            new LdapBindAuthenticationManagerFactory(contextSource);

        factory.setUserDnPatterns("uid={0},ou=people");

        factory.setUserDetailsContextMapper(new PersonContextMapper());

        return factory.createAuthenticationManager();

    }

}

JDBC身份验证

下面是一个使用WebSecurityConfigurerAdapter的配置示例,其中嵌入了一个用默认模式初始化的数据源,并且只有一个用户:

@Configuration

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Bean

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder()

            .setType(EmbeddedDatabaseType.H2)

            .build();

    }

    @Override

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        UserDetails user = User.withDefaultPasswordEncoder()

            .username("user")

            .password("password")

            .roles("USER")

            .build();

        auth.jdbcAuthentication()

            .withDefaultSchema()

            .dataSource(dataSource())

            .withUser(user);

    }

}

推荐的方法是注册一个JdbcUserDetailsManager bean:

@Configuration

public class SecurityConfiguration {

    @Bean

    public DataSource dataSource() {

        return new EmbeddedDatabaseBuilder()

            .setType(EmbeddedDatabaseType.H2)

            .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)

            .build();

    }

    @Bean

    public UserDetailsManager users(DataSource dataSource) {

        UserDetails user = User.withDefaultPasswordEncoder()

            .username("user")

            .password("password")

            .roles("USER")

            .build();

        JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);

        users.createUser(user);

        return users;

    }

}

注意:在这些示例中,为了提高可读性,我们使用了User.withDefaultPasswordEncoder()方法。它不是用于生产环境的,相反,我们建议在外部散列您的密码。一种方法是使用参考文档中描述的Spring Boot CLI。

内存中的身份验证

下面是一个使用WebSecurityConfigurerAdapter的配置示例,它用单个用户配置内存中的用户存储:

@Configuration

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        UserDetails user = User.withDefaultPasswordEncoder()

            .username("user")

            .password("password")

            .roles("USER")

            .build();

        auth.inMemoryAuthentication()

            .withUser(user);

    }

}

推荐的方法是注册一个InMemoryUserDetailsManager bean:

@Configuration

public class SecurityConfiguration {

    @Bean

    public InMemoryUserDetailsManager userDetailsService() {

        UserDetails user = User.withDefaultPasswordEncoder()

            .username("user")

            .password("password")

            .roles("USER")

            .build();

        return new InMemoryUserDetailsManager(user);

    }

}

注意:在这些示例中,为了提高可读性,我们使用了User.withDefaultPasswordEncoder()方法。它不是用于生产环境的,相反,我们建议在外部散列您的密码。一种方法是使用参考文档中描述的Spring Boot CLI。

全局AuthenticationManager

要创建一个对整个应用程序可用的AuthenticationManager,只需将AuthenticationManager注册为@Bean即可。

在上面的LDAP身份验证示例中显示了这种类型的配置。

https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter#ldap-authentication

本地AuthenticationManager

在Spring Security 5.6中,我们引入了httpsecurity# authenticationManager方法,它覆盖了特定SecurityFilterChain的默认authenticationManager。下面是一个将自定义AuthenticationManager设置为默认值的示例配置:

@Configuration

public class SecurityConfiguration {

    @Bean

    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http

            .authorizeHttpRequests((authz) -> authz

                .anyRequest().authenticated()

            )

            .httpBasic(withDefaults())

            .authenticationManager(new CustomAuthenticationManager());

        return http.build();

    }

}

访问本地AuthenticationManager

本地AuthenticationManager可以在自定义DSL中访问。这实际上是Spring Security内部实现HttpSecurity.authorizeRequests()等方法的方式。

public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {

    @Override

    public void configure(HttpSecurity http) throws Exception {

        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);

        http.addFilter(new CustomFilter(authenticationManager));

    }

    public static MyCustomDsl customDsl() {

        return new MyCustomDsl();

    }

}

自定义DSL可以在构建SecurityFilterChain时应用:

@Bean

public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

    // ...

    http.apply(customDsl());

    return http.build();

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。