Spring Security 7.0版本将彻底移除传统的链式配置方式,开发者必须迁移到全新的Lambda DSL配置方式。这是一个重大的突破性变更(Breaking Change),需要所有使用Spring Security的项目进行相应的代码调整。
Lambda DSL 配置方式
如上写法被 Spring Security 标记为过时用法,从Spring Security 5.2版本开始引入的Lambda DSL配置方式,将在7.0版本成为唯一支持的配置方式。让我们通过实例来了解这种配置方式。
传统配置方式的问题
传统配置方式存在以下问题:
- 使用
.and()
方法链接配置块,导致代码嵌套层级深、可读性差
- 配置块之间的关系不够清晰,容易混淆作用域
- IDE 难以提供准确的代码补全和类型提示
- 配置错误只能在运行时才能发现
Lambda DSL 的优势
相比之下,Lambda DSL 配置方式具有以下优点:
- 更清晰的层级结构,每个配置块都有明确的作用域
- 更好的类型安全,编译时就能发现配置错误
- IDE 可以提供更准确的代码补全
- 配置逻辑更容易重用和组合
- 代码更简洁,无需使用
.and()
方法
例如,以下是一个典型的 Lambda DSL 配置:
新旧配置方式对比
使用 Lambda DSL 的配置方式(推荐)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/token/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.loginPage("/login")
.permitAll()
)
.rememberMe(Customizer.withDefaults());
return http.build();
}
}
传统配置方式(将在7.0中移除)
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers("/token/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.rememberMe();
return http.build();
}
}
为什么要强制使用 Lambda DSL?
Spring Security团队决定在7.0版本中强制使用Lambda DSL,主要基于以下考虑:
-
更清晰的配置层次:传统配置方式中,如果不了解返回类型,很难理解正在配置的对象。配置嵌套越深,理解起来就越困难。
-
一致性:许多代码库在两种风格之间切换,导致配置不一致,增加了理解难度,容易引起配置错误。
Lambda DSL 使用技巧
在使用Lambda DSL时,需要注意以下几点:
-
无需使用.and():Lambda DSL配置中不再需要使用.and()
方法链接配置选项。HttpSecurity实例会在lambda方法调用后自动返回,用于进一步配置。
-
默认配置简写:使用Customizer.withDefaults()
可以启用Spring Security提供的默认配置,这是it -> {}
lambda表达式的简写形式。
WebFlux 安全配置
WebFlux的安全配置同样支持Lambda DSL,示例如下:
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/blog/**").permitAll()
.anyExchange().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(formLogin -> formLogin
.loginPage("/login")
);
return http.build();
}
}
Lambda DSL 的设计目标
Lambda DSL的设计目标包括:
- 自动缩进:通过IDE的自动缩进功能,使配置更易读。
- 移除.and():不再需要使用
.and()
方法链接配置。
- 统一风格:与Spring Integration和Spring Cloud Gateway等其他Spring DSL保持一致的配置风格。
自定义DSL的变更
从6.2版本开始,对于自定义DSL:
- 废弃:
HttpSecurity#apply(…)
方法
- 推荐:使用新的
.with(…)
方法
这一变更是由于在7.0版本中将完全移除.and()
方法。
如何创建自定义DSL
在Spring Security中,你可以创建自己的自定义DSL。以下是一个完整的示例:
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
private boolean flag;
@Override
public void init(HttpSecurity http) throws Exception {
// 在init方法中添加其他配置器
// 例如禁用CSRF
http.csrf().disable();
}
@Override
public void configure(HttpSecurity http) throws Exception {
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
// 从ApplicationContext中获取Bean,也可以直接创建新实例
MyFilter myFilter = context.getBean(MyFilter.class);
myFilter.setFlag(flag);
http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
}
public MyCustomDsl flag(boolean value) {
this.flag = value;
return this;
}
public static MyCustomDsl customDsl() {
return new MyCustomDsl();
}
}
这实际上就是Spring Security内部实现HttpSecurity.authorizeHttpRequests()
等方法的方式。
使用自定义DSL
在配置类中,你可以这样使用自定义DSL:
@Configuration
@EnableWebSecurity
public class Config {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.with(MyCustomDsl.customDsl(), (dsl) -> dsl
.flag(true)
)
// ... 其他配置
return http.build();
}
}
在创建自定义DSL时,请注意以下几点:
- 继承
AbstractHttpConfigurer
类,它提供了必要的基础设施
- 在
init
方法中添加其他配置器
- 在
configure
方法中实现具体的安全配置逻辑
- 提供流式API以保持配置风格的一致性
- 使用静态工厂方法来创建DSL实例
Spring Security 7.0的配置变更主要围绕Lambda DSL展开,这种变更将带来更清晰、一致的配置体验。建议开发团队及早开始相关迁移工作,以确保顺利过渡到新版本。