对于最新的稳定版本,请使用 Spring Security 6.5.3! |
配置迁移
以下步骤与有关如何配置的更改有关HttpSecurity
,WebSecurity
和AuthenticationManager
.
加@Configuration
注解
在 6.0 中,@Configuration
从@EnableWebSecurity
,@EnableMethodSecurity
,@EnableGlobalMethodSecurity
和@EnableGlobalAuthentication
.
为了为此做好准备,无论您在哪里使用这些注解之一,您都可能需要将@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
方法被弃用,取而代之的是新的requestMatchers
方法.
新的requestMatchers
添加了方法自authorizeHttpRequests
,authorizeRequests
、CSRF配置、WebSecurityCustomizer
以及任何其他有专门的地方RequestMatcher
方法。
已弃用的方法已在 Spring Security 6 中删除。
这些新方法具有更安全的默认值,因为它们选择了最合适的RequestMatcher
实现。
总之,新方法选择了MvcRequestMatcher
如果您的应用程序在类路径中有 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
您正在使用的实现。
例如,如果您仍然想使用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
方法 来自HttpSecurity
被弃用,取而代之的是新的securityMatchers
方法。
请注意,这些方法与authorizeHttpRequests
被弃用的方法,取而代之的是requestMatchers
方法。
但是,securityMatchers
方法类似于requestMatchers
方法,即他们会选择最合适的方法RequestMatcher
实现。
总之,新方法选择了MvcRequestMatcher
如果您的应用程序在类路径中有 Spring MVC,则回退到AntPathRequestMatcher
如果 Spring MVC 不存在,则实现(使行为与 Kotlin 等效方法保持一致)。
添加securityMatchers
方法是避免与requestMatchers
方法 来自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
实现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
实现,您可以随时选择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()
对于内存中身份验证支持,您可以将:
-
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)
在 Spring Framework 中提供了另一个删除@Configuration
meta-comments 来自 Spring Security 的@Enable*
注释,并允许用户选择加入他们首选的配置模式。
以下注释具有@Configuration
删除:
-
@EnableGlobalAuthentication
-
@EnableGlobalMethodSecurity
-
@EnableMethodSecurity
-
@EnableReactiveMethodSecurity
-
@EnableWebSecurity
-
@EnableWebFluxSecurity
例如,如果您使用@EnableWebSecurity
,您将需要更改:
-
Java
@EnableWebSecurity
public class SecurityConfig {
// ...
}
自:
-
Java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
// ...
}
这同样适用于上面列出的所有其他注释。
其他场景
如果您正在使用AuthenticationManagerBuilder
对于更复杂的东西,您可以发布您自己的AuthenticationManager
@Bean
或将AuthenticationManager
实例转换为HttpSecurity
DSL 与HttpSecurity#authenticationManager
.