此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.3spring-doc.cadn.net.cn

配置迁移

以下步骤与有关如何配置的更改相关HttpSecurity,WebSecurityAuthenticationManager.spring-doc.cadn.net.cn

@Configuration注解

在 6.0 中,@Configuration已从@EnableWebSecurity,@EnableMethodSecurity,@EnableGlobalMethodSecurity@EnableGlobalAuthentication.spring-doc.cadn.net.cn

为此,无论您在何处使用这些 annotation 之一,都可能需要添加@Configuration. 例如@EnableMethodSecurity更改:spring-doc.cadn.net.cn

@EnableMethodSecurity
public class MyConfiguration {
	// ...
}
@EnableMethodSecurity
open class MyConfiguration {
	// ...
}
@Configuration
@EnableMethodSecurity
public class MyConfiguration {
	// ...
}
@Configuration
@EnableMethodSecurity
open class MyConfiguration {
	// ...
}

使用新的requestMatchers方法

在 Spring Security 5.8 中,antMatchers,mvcMatchersregexMatchers方法已被弃用,取而代使用的 newrequestMatchers方法.spring-doc.cadn.net.cn

新的requestMatchers添加了 methodsauthorizeHttpRequests,authorizeRequests、CSRF 配置、WebSecurityCustomizer以及任何其它具有RequestMatcher方法。 已弃用的方法在 Spring Security 6 中删除。spring-doc.cadn.net.cn

这些新方法具有更安全的默认值,因为它们选择了最合适的RequestMatcher实现。 总之,新方法选择MvcRequestMatcherimplementation (如果您的应用程序在 Classpath 中有 Spring MVC),则回退到AntPathRequestMatcher如果 Spring MVC 不存在,则实现(将行为与 Kotlin 等效方法保持一致)。spring-doc.cadn.net.cn

要开始使用新方法,您可以将已弃用的方法替换为新方法。例如,以下应用程序配置:spring-doc.cadn.net.cn

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .antMatchers("/api/admin/**").hasRole("ADMIN")
                .antMatchers("/api/user/**").hasRole("USER")
                .anyRequest().authenticated()
            );
        return http.build();
    }

}

可以更改为:spring-doc.cadn.net.cn

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .requestMatchers("/api/user/**").hasRole("USER")
                .anyRequest().authenticated()
            );
        return http.build();
    }

}

如果您在类路径中有 Spring MVC,并且正在使用mvcMatchers方法,您可以将其替换为新方法,Spring Security 将选择MvcRequestMatcher实施。 以下配置:spring-doc.cadn.net.cn

@Configuration
@EnableWebSecurity
@EnableWebMvc
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .mvcMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            );
        return http.build();
    }

}
@Configuration
@EnableWebSecurity
@EnableWebMvc
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            );
        return http.build();
    }

}

如果要自定义servletPath属性的MvcRequestMatcher,您现在可以使用MvcRequestMatcher.Builder创建MvcRequestMatcher共享同一 servlet 路径的实例:spring-doc.cadn.net.cn

@Configuration
@EnableWebSecurity
@EnableWebMvc
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .mvcMatchers("/admin").servletPath("/path").hasRole("ADMIN")
                .mvcMatchers("/user").servletPath("/path").hasRole("USER")
                .anyRequest().authenticated()
            );
        return http.build();
    }

}

上面的代码可以使用MvcRequestMatcher.BuilderrequestMatchers方法:spring-doc.cadn.net.cn

@Configuration
@EnableWebSecurity
@EnableWebMvc
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception {
        MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector).servletPath("/path");
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers(mvcMatcherBuilder.pattern("/admin")).hasRole("ADMIN")
                .requestMatchers(mvcMatcherBuilder.pattern("/user")).hasRole("USER")
                .anyRequest().authenticated()
            );
        return http.build();
    }

}

如果您在使用新的requestMatchers方法,您始终可以切换回RequestMatcherimplementation 中。 例如,如果您仍希望使用AntPathRequestMatcherRegexRequestMatcher实现中,您可以使用requestMatchers接受RequestMatcher实例:spring-doc.cadn.net.cn

import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
import static org.springframework.security.web.util.matcher.RegexRequestMatcher.regexMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .requestMatchers(antMatcher("/user/**")).hasRole("USER")
                .requestMatchers(antMatcher(HttpMethod.POST, "/user/**")).hasRole("ADMIN")
                .requestMatchers(regexMatcher(".*\\?x=y")).hasRole("SPECIAL") // matches /any/path?x=y
                .anyRequest().authenticated()
            );
        return http.build();
    }

}

Note that the above sample uses static factory methods from AntPathRequestMatcher and RegexRequestMatcher to improve readability.spring-doc.cadn.net.cn

If you are using the WebSecurityCustomizer interface, you can replace the deprecated antMatchers methods:spring-doc.cadn.net.cn

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
	return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");
}

with their requestMatchers counterparts:spring-doc.cadn.net.cn

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
	return (web) -> web.ignoring().requestMatchers("/ignore1", "/ignore2");
}

The same way, if you are customizing the CSRF configuration to ignore some paths, you can replace the deprecated methods with the requestMatchers methods:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .csrf((csrf) -> csrf
            .ignoringAntMatchers("/no-csrf")
        );
    return http.build();
}

can be changed to:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .csrf((csrf) -> csrf
            .ignoringRequestMatchers("/no-csrf")
        );
    return http.build();
}

Use the new securityMatchers methods

In Spring Security 5.8, the antMatchers, mvcMatchers and requestMatchers methods from HttpSecurity were deprecated in favor of new securityMatchers methods.spring-doc.cadn.net.cn

Note that these methods are not the same from authorizeHttpRequests methods which were deprecated in favor of the requestMatchers methods. However, the securityMatchers methods are similar to the requestMatchers methods in the sense that they will choose the most appropriate RequestMatcher implementation for your application. In summary, the new methods choose the MvcRequestMatcher implementation if your application has Spring MVC in the classpath, falling back to the AntPathRequestMatcher implementation if Spring MVC is not present (aligning the behavior with the Kotlin equivalent methods). Another reason for adding the securityMatchers methods is to avoid confusion with the requestMatchers methods from authorizeHttpRequests.spring-doc.cadn.net.cn

The following configuration:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .antMatcher("/api/**", "/app/**")
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

can be rewritten using the securityMatchers methods:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher("/api/**", "/app/**")
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

If you are using a custom RequestMatcher in your HttpSecurity configuration:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .requestMatcher(new MyCustomRequestMatcher())
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

public class MyCustomRequestMatcher implements RequestMatcher {
	// ...
}

you can do the same using securityMatcher:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher(new MyCustomRequestMatcher())
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/api/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

public class MyCustomRequestMatcher implements RequestMatcher {
	// ...
}

If you are combining multiple RequestMatcher implementations in your HttpSecurity configuration:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .requestMatchers((matchers) -> matchers
            .antMatchers("/api/**", "/app/**")
            .mvcMatchers("/admin/**")
            .requestMatchers(new MyCustomRequestMatcher())
        )
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

you can change it by using securityMatchers:spring-doc.cadn.net.cn

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .securityMatchers((matchers) -> matchers
            .requestMatchers("/api/**", "/app/**", "/admin/**")
            .requestMatchers(new MyCustomRequestMatcher())
        )
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

If you are having problems with the securityMatchers methods choosing the RequestMatcher implementation for you, you can always choose the RequestMatcher implementation yourself:spring-doc.cadn.net.cn

import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .securityMatchers((matchers) -> matchers
            .requestMatchers(antMatcher("/api/**"), antMatcher("/app/**"))
        )
        .authorizeHttpRequests((authz) -> authz
            .requestMatchers(antMatcher("/api/admin/**")).hasRole("ADMIN")
            .anyRequest().authenticated()
        );
    return http.build();
}

Stop Using WebSecurityConfigurerAdapter

Publish a SecurityFilterChain Bean

Spring Security 5.4 introduced the capability to publish a SecurityFilterChain bean instead of extending WebSecurityConfigurerAdapter. In 6.0, WebSecurityConfigurerAdapter is removed. To prepare for this change, you can replace constructs like:spring-doc.cadn.net.cn

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
    }

}
@Configuration
open class SecurityConfiguration: WebSecurityConfigurerAdapter() {

    @Override
    override fun configure(val http: HttpSecurity) {
        http {
            authorizeHttpRequests {
                authorize(anyRequest, authenticated)
            }

            httpBasic {}
        }
    }

}
@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
        return http.build();
    }

}
@Configuration
open class SecurityConfiguration {

    @Bean
    fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            authorizeHttpRequests {
                authorize(anyRequest, authenticated)
            }
            httpBasic {}
        }
        return http.build()
    }

}

Publish a WebSecurityCustomizer Bean

Spring Security 5.4 introduced WebSecurityCustomizer to replace configure(WebSecurity web) in WebSecurityConfigurerAdapter. To prepare for its removal, you can replace code like the following:spring-doc.cadn.net.cn

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/ignore1", "/ignore2");
    }

}
@Configuration
open class SecurityConfiguration: WebSecurityConfigurerAdapter() {

    override fun configure(val web: WebSecurity) {
        web.ignoring().antMatchers("/ignore1", "/ignore2")
    }

}
@Configuration
public class SecurityConfiguration {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");
    }

}
@Configuration
open class SecurityConfiguration {

    @Bean
    fun webSecurityCustomizer(): WebSecurityCustomizer {
        return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2")
    }

}

Publish an AuthenticationManager Bean

As part of WebSecurityConfigurerAdapter removal, configure(AuthenticationManagerBuilder) is also removed. Preparing for its removal will differ based on your reason for using it.spring-doc.cadn.net.cn

LDAP Authentication

If you are using auth.ldapAuthentication() for LDAP authentication support, you can replace:spring-doc.cadn.net.cn

@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);
    }

}
@Configuration
open class SecurityConfiguration: WebSecurityConfigurerAdapter() {

    override fun configure(auth: AuthenticationManagerBuilder) {
        auth
            .ldapAuthentication()
                .userDetailsContextMapper(PersonContextMapper())
                .userDnPatterns("uid={0},ou=people")
                .contextSource()
                .port(0)
    }

}
@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();
    }
}
@Configuration
open class SecurityConfiguration {
    @Bean
    fun contextSourceFactoryBean(): EmbeddedLdapServerContextSourceFactoryBean {
        val contextSourceFactoryBean: EmbeddedLdapServerContextSourceFactoryBean =
            EmbeddedLdapServerContextSourceFactoryBean.fromEmbeddedLdapServer()
        contextSourceFactoryBean.setPort(0)
        return contextSourceFactoryBean
    }

    @Bean
    fun ldapAuthenticationManager(val contextSource: BaseLdapPathContextSource): AuthenticationManager {
        val factory = LdapBindAuthenticationManagerFactory(contextSource)
        factory.setUserDnPatterns("uid={0},ou=people")
        factory.setUserDetailsContextMapper(PersonContextMapper())
        return factory.createAuthenticationManager()
    }
}

JDBC Authentication

If you are using auth.jdbcAuthentication() for JDBC Authentication support, you can replace:spring-doc.cadn.net.cn

@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(this.dataSource)
                .withUser(user);
    }
}
@Configuration
open class SecurityConfiguration: WebSecurityConfigurerAdapter() {
    @Bean
    fun dataSource(): DataSource {
        return EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .build()
    }

    override fun configure(val auth: AuthenticationManagerBuilder) {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build()
        auth.jdbcAuthentication()
            .withDefaultSchema()
                .dataSource(this.dataSource)
                .withUser(user)
    }
}
@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;
    }
}
@Configuration
open class SecurityConfiguration {
    @Bean
    fun dataSource(): DataSource {
        return EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.H2)
            .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)
            .build()
    }

    @Bean
    fun users(val dataSource: DataSource): UserDetailsManager {
        val user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build()
        val users = JdbcUserDetailsManager(dataSource)
        users.createUser(user)
        return users
    }
}

In-Memory Authentication

If you are using auth.inMemoryAuthentication() for In-Memory Authentication support, you can replace:spring-doc.cadn.net.cn

@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);
    }
}
@Configuration
open class SecurityConfiguration: WebSecurityConfigurerAdapter() {
    override fun configure(val auth: AuthenticationManagerBuilder) {
        val user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build()
        auth.inMemoryAuthentication()
            .withUser(user)
    }
}
@Configuration
public class SecurityConfiguration {
    @Bean
    public InMemoryUserDetailsManager userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }
}
@Configuration
open class SecurityConfiguration {
    @Bean
    fun userDetailsService(): InMemoryUserDetailsManager {
        UserDetails user = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build()
        return InMemoryUserDetailsManager(user)
    }
}

Add @Configuration to @Enable* annotations

In 6.0, all Spring Security’s @Enable* annotations had their @Configuration removed. While convenient, it was not consistent with the rest of the Spring projects and most notably Spring Framework’s @Enable* annotations. Additionally, the introduction of support for @Configuration(proxyBeanMethods=false) in Spring Framework provides another reason to remove @Configuration meta-annotation from Spring Security’s @Enable* annotations and allow users to opt into their preferred configuration mode.spring-doc.cadn.net.cn

The following annotations had their @Configuration removed:spring-doc.cadn.net.cn

For example, if you are using @EnableWebSecurity, you will need to change:spring-doc.cadn.net.cn

@EnableWebSecurity
public class SecurityConfig {
	// ...
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
	// ...
}

And the same applies to every other annotation listed above.spring-doc.cadn.net.cn

Other Scenarios

If you are using AuthenticationManagerBuilder for something more sophisticated, you can publish your own AuthenticationManager @Bean or wire an AuthenticationManager instance into the HttpSecurity DSL with HttpSecurity#authenticationManager.spring-doc.cadn.net.cn