对于最新的稳定版本,请使用 Spring Security 6.5.0! |
配置迁移
以下步骤与有关如何配置的更改相关HttpSecurity
,WebSecurity
和AuthenticationManager
.
加@Configuration
注解
在 6.0 中,@Configuration
已从@EnableWebSecurity
,@EnableMethodSecurity
,@EnableGlobalMethodSecurity
和@EnableGlobalAuthentication
.
为此,无论您在何处使用这些 annotation 之一,都可能需要添加@Configuration
.
例如@EnableMethodSecurity
更改:
-
Java
@EnableMethodSecurity
public class MyConfiguration {
// ...
}
-
Kotlin
@EnableMethodSecurity
open class MyConfiguration {
// ...
}
自:
-
Java
@Configuration
@EnableMethodSecurity
public class MyConfiguration {
// ...
}
-
Kotlin
@Configuration
@EnableMethodSecurity
open class MyConfiguration {
// ...
}
使用新的requestMatchers
方法
在 Spring Security 5.8 中,antMatchers
,mvcMatchers
和regexMatchers
方法已被弃用,取而代使用的 newrequestMatchers
方法.
新的requestMatchers
添加了 methods自authorizeHttpRequests
,authorizeRequests
、CSRF 配置、WebSecurityCustomizer
以及任何其它具有RequestMatcher
方法。
已弃用的方法在 Spring Security 6 中删除。
这些新方法具有更安全的默认值,因为它们选择了最合适的RequestMatcher
实现。
总之,新方法选择MvcRequestMatcher
implementation (如果您的应用程序在 Classpath 中有 Spring MVC),则回退到AntPathRequestMatcher
如果 Spring MVC 不存在,则实现(使行为与 Kotlin 等效方法保持一致)。
要开始使用新方法,您可以将已弃用的方法替换为新方法。例如,以下应用程序配置:
-
Java
@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();
}
}
可以更改为:
-
Java
@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
实施。
以下配置:
-
Java
@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();
}
}
等效于:
-
Java
@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 路径的实例:
-
Java
@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.Builder
和requestMatchers
方法:
-
Java
@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
方法,您始终可以切换回RequestMatcher
implementation 中。
例如,如果您仍希望使用AntPathRequestMatcher
和RegexRequestMatcher
实现中,您可以使用requestMatchers
接受RequestMatcher
实例:
-
Java
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();
}
}
请注意,上面的示例使用了AntPathRequestMatcher
和RegexRequestMatcher
以提高可读性。
如果您使用的是WebSecurityCustomizer
接口中,您可以将已弃用的antMatchers
方法:
-
Java
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");
}
替换为他们的requestMatchers
同行:
-
Java
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().requestMatchers("/ignore1", "/ignore2");
}
同样,如果你正在自定义 CSRF 配置以忽略某些路径,你可以将已弃用的方法替换为requestMatchers
方法:
-
Java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf((csrf) -> csrf
.ignoringAntMatchers("/no-csrf")
);
return http.build();
}
可以更改为:
-
Java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf((csrf) -> csrf
.ignoringRequestMatchers("/no-csrf")
);
return http.build();
}
使用新的securityMatchers
方法
在 Spring Security 5.8 中,antMatchers
,mvcMatchers
和requestMatchers
methods 从HttpSecurity
被弃用,取而代使用的securityMatchers
方法。
请注意,这些方法与authorizeHttpRequests
方法已被弃用,取而代之的是requestMatchers
方法。
但是,securityMatchers
方法类似于requestMatchers
方法,因为他们将选择最合适的RequestMatcher
实现。
总之,新方法选择MvcRequestMatcher
implementation (如果您的应用程序在 Classpath 中有 Spring MVC),则回退到AntPathRequestMatcher
如果 Spring MVC 不存在,则实现(将行为与 Kotlin 等效方法保持一致)。
添加securityMatchers
方法是为了避免与requestMatchers
methods 从authorizeHttpRequests
.
以下配置:
-
Java
@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();
}
可以使用securityMatchers
方法:
-
Java
@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();
}
如果您使用的是自定义RequestMatcher
在HttpSecurity
配置:
-
Java
@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 {
// ...
}
您可以使用securityMatcher
:
-
Java
@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 {
// ...
}
如果要合并多个RequestMatcher
implementations 在HttpSecurity
配置:
-
Java
@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();
}
您可以使用securityMatchers
:
-
Java
@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();
}
如果您在使用securityMatchers
方法选择RequestMatcher
implementation 中,您始终可以选择RequestMatcher
自行实现:
-
Java
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();
}
停止使用WebSecurityConfigurerAdapter
发布SecurityFilterChain
豆
Spring Security 5.4 引入了发布SecurityFilterChain
bean 而不是扩展WebSecurityConfigurerAdapter
.
在 6.0 中,WebSecurityConfigurerAdapter
已删除。
要为此更改做好准备,您可以替换如下结构:
-
Java
-
Kotlin
@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 {}
}
}
}
跟:
-
Java
-
Kotlin
@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()
}
}
发布WebSecurityCustomizer
豆
Spring Security 5.4介绍WebSecurityCustomizer
将configure(WebSecurity web)
在WebSecurityConfigurerAdapter
.
要准备将其删除,您可以替换如下代码:
-
Java
-
Kotlin
@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")
}
}
跟:
-
Java
-
Kotlin
@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")
}
}
发布AuthenticationManager
豆
作为WebSecurityConfigurerAdapter
免职configure(AuthenticationManagerBuilder)
也会被删除。
准备删除它会因您使用它的原因而异。
LDAP 身份验证
如果您正在使用auth.ldapAuthentication()
对于 LDAP 身份验证支持,您可以替换:
-
Java
-
Kotlin
@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)
}
}
跟:
-
Java
-
Kotlin
@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 身份验证
如果您正在使用auth.jdbcAuthentication()
对于 JDBC 身份验证支持,您可以替换:
-
Java
-
Kotlin
@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)
}
}
跟:
-
Java
-
Kotlin
@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
}
}
内存中身份验证
如果您正在使用auth.inMemoryAuthentication()
对于 In-Memory Authentication 支持,您可以替换:
-
Java
-
Kotlin
@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)
}
}
跟:
-
Java
-
Kotlin
@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)
}
}
加@Configuration
自@Enable*
附注
在 6.0 中,所有 Spring Security 的@Enable*
注释具有@Configuration
删除。
虽然方便,但它与其他 Spring 项目不一致,尤其是 Spring Framework 的@Enable*
附注。
此外,引入了对@Configuration(proxyBeanMethods=false)
提供了另一个将@Configuration
来自 Spring Security 的 meta-annotation@Enable*
注释,并允许用户选择加入他们的首选配置模式。
以下注释具有@Configuration
删除:
-
@EnableGlobalAuthentication
-
@EnableGlobalMethodSecurity
-
@EnableMethodSecurity
-
@EnableReactiveMethodSecurity
-
@EnableWebSecurity
-
@EnableWebFluxSecurity
例如,如果您正在使用@EnableWebSecurity
,您将需要更改:
-
Java
@EnableWebSecurity
public class SecurityConfig {
// ...
}
自:
-
Java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// ...
}
这同样适用于上面列出的所有其他 Comments。
其他场景
如果您正在使用AuthenticationManagerBuilder
对于更复杂的内容,您可以发布您自己的AuthenticationManager
@Bean
或连接AuthenticationManager
实例到HttpSecurity
DSL 替换为HttpSecurity#authenticationManager
.