Spring Security 实战干货:5.4版本带来的新玩法
1. 前言
在以往Spring Security的教程中我们自定义配置都是声明一个配置类WebSecurityConfigurerAdapter
,然后覆写(@Override
)对应的几个方法就行了。然而这一切在Spring Security 5.4开始就得到了改变,从Spring Security 5.4 起我们不需要继承WebSecurityConfigurerAdapter
就可以配置HttpSecurity
了。相关的说明原文:
Remove need for WebSecurityConfigurerAdapter #8805 Configure HTTP Security without extending WebSecurityConfigurerAdapter #8804
❝发稿时最新的Spring Security版本为 5.4.5。
2. 新的配置方式
旧的配置方式目前依然有效:
@Configuration
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests(authorize -> authorize
.anyRequest().authenticated()
);
}
}
5.4.x版本我们有新的选择:
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.antMatcher("/**")
.authorizeRequests(authorize -> authorize
.anyRequest().authenticated()
)
.build();
}
这种JavaConfig的方式看起来更加清爽舒服,而且和适配器解耦了。等等我好像发现了新的东西,上面filterChain
方法的参数是HttpSecurity
类型。熟悉@Bean
注解的同学应该会意识到一定有一个HttpSecurity
类型的Spring Bean。没错!就在HttpSecurityConfiguration
中有一个这样的Bean:
@Bean({"org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.httpSecurity"})
@Scope("prototype")
HttpSecurity httpSecurity() throws Exception {
// 省略掉
return http;
}
初始化的内容已经忽略掉,它不是本文关注的重点。我们注意到HttpSecurity
被@Scope("prototype")
标记。也就是这个HttpSecurity
Bean不是单例的,每一次请求都会构造一个新的实例。这个设定非常方便我们构建多个互相没有太多关联的SecurityFilterChain
,进而能在一个安全体系中构建相互隔离的安全策略。比如后端管理平台用Session模式,前台应用端用Token模式。
3. 原理
Spring Security 有一个名为springSecurityFilterChain
默认的过滤器链类(实际位置就是上图的 Bean Filter位置),其类型为FilterChainProxy
, 它代理了所有的SecurityFilterChain
,关键的代理注入代码:
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break;
}
}
}
那么this.securityFilterChains
来自哪里呢?
@Autowired(required = false)
void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
securityFilterChains.sort(AnnotationAwareOrderComparator.INSTANCE);
this.securityFilterChains = securityFilterChains;
}
到这里就一目了然了吧,SecurityFilterChain
类型的Bean会被加载到this.securityFilterChains
中。如果你的Spring Security 版本升级到 5.4.x,就可以尝试一下这种方式。我是:码农小胖哥 别忘了转发、再看、点赞。
2021-03-22
2021-03-21
2021-03-19