接上一篇文章。
我们已经完成了对配置类HttpSecurityConfiguration、以及通过配置类创建安全构建起HttpSecurity的源码分析(当然是我们所关注的主要部分、而非全部),而且知道通过安全构建起HttpSecurity创建DefaultSecurityFilterChain的过程。
我们再不厌其烦的简单回忆一下,DefaultSecurityFilterChain持有Spring Security的各安全过滤器,它最终会装配到filterChainProxy中,filterChainProxy再装配到DelegatingFilterProxy中并最终在Servlet的过滤器链中生效。
所以,接下来我们就要找到DefaultSecurityFilterChain是怎么装配到filterChainProxy中的。
我们从WebSecurityConfiguration入手,从spring.factories文件中能找到SpringBoot的自动化装配机制对它的调用入口。
WebSecurityConfiguration#setFilterChains
首先看一下他的setFilterChains方法:
@Autowired(required = false)
void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
this.securityFilterChains = securityFilterChains;
}
方法加了@Autowired注解,方法参数为List<SecurityFilterChain> securityFilterChains,所以这个参数要从Spring Ioc容器中拿到,我们知道securityFilterChains的唯一实现类是DefaultSecurityFilterChain,上一篇文章已经分析过了他的初始化过程,因此,我们可以知道这个方法调用之后,DefaultSecurityFilterChain会赋值给WebSecurityConfiguration对象的securityFilterChains属性。
WebSecurityConfiguration#springSecurityFilterChain
接下来看springSecurityFilterChain方法,我们分段分析:
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
//省略部分代码...
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break;
}
}
}
首先遍历当前对象的securityFilterChains,上面我们已经分析过了,securityFilterChains存放的是DefaultSecurityFilterChain对象。然后使用该对象作为参数调用this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);方法。
WebSecurity#addSecurityFilterChainBuilder
注意这个方法的参数类型为SecurityBuilder<? extends SecurityFilterChain> ,我们先看一下它的定义:
public interface SecurityBuilder<O> {
/**
* Builds the object and returns it or null.
* @return the Object to be built or null if the implementation allows it.
* @throws Exception if an error occurred when building the Object
*/
O build() throws Exception;
}
该接口只有一个build方法,build方法返回泛型O。
我们必须注意这个方法的调用方式:
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
使用lamda方式调用,实现了接口SecurityBuilder的build()方法,返回DefaultSecurityFilterChain对象。
最后再来看这个addSecurityFilterChainBuilder方法,其实很简单,把传进来的这个通过lamda实现了的对象加入WebSecurity对象的securityFilterChainBuilders中。
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
WebSecurityConfiguration#springSecurityFilterChain
然后再继续返回来看springSecurityFilterChain()方法的剩余部分:调用webSecurity的build()方法:
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
return this.webSecurity.build();
AbstractSecurityBuilder#build
Build方法在AbstractSecurityBuilder类实现,似曾相识:
@Override
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
是的没错,和我们上一篇文章分析过的HttpSecurityConfig的build方法如出一辙。
他们调用到AbstractConfigedSecurityBuilder的dobuild方法,我们上一篇文章分析过他的configure和performBuild两个方法,那是因为HttpSecurity包含了一堆安全过滤器的配置器,所以configure方法比较重要,但是WebSecurity中并没有包含过滤器的配置器,所以,configure方法也不是很重要。
我们还不如就直捣黄龙。
WebSecurity#performBuild
代码虽然不是很多但是很重要,所以还是分段分析:
@Override
protected Filter performBuild() throws Exception {
//此处省略掉一堆不重要的代码
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
SecurityFilterChain securityFilterChain = securityFilterChainBuilder.build();
securityFilterChains.add(securityFilterChain);
requestMatcherPrivilegeEvaluatorsEntries
.add(getRequestMatcherPrivilegeEvaluatorsEntry(securityFilterChain));
}
首先从securityFilterChainBuilders中取出securityFilterChainBuilder,调用build方法。
这个地方需要呼应我们上面说过的通过lamda创建securityFilterChainBuilder的过程,他的build方法最终就会返回DefaultSecurityFilterChain对象!!!
然后把它加入到securityFilterChains列表中。
再来看下一段代码:
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
filterChainProxy.afterPropertiesSet();
出现了一个我们期待已久的对象FilterChainProxy:创建FilterChainProxy对象并且把DefaultSecurityFilterChain作为参数传递给FilterChainProxy,让FilterChainProxy持有DefaultSecurityFilterChain对象!
然后就是一些后处理,最终返回FilterChainProxy:
Filter result = filterChainProxy;
...
this.postBuildAction.run();
return result;
FilterChainProxy加入Spring Ioc容器
最后再看一眼springSecurityFilterChain方法的定义,FilterChainProxy创建后,通过@Bean注解加入到Spring Ioc容器中进行管理,命名为AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME:
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
而AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME定义为:
public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";
所以我们要加深一下印象,Spring Ioc容器中名字为springSecurityFilterChain的bean对应的对象是FilterChainProxy。
我们再来回忆一下:
上图中右半部分的DefaultSecurityFilterChain已经装配好、左边的FilterChainProxy也已经装配好,并且,DefaultSecurityFilterChain的各过滤器已经准备完毕。
万事俱备,只欠东风:FilterChainProxy装配到DeletatingFilterProxy中,然后再研究一下DeletatingFilterProxy是怎么配置到Servlet的过滤器链(FilterChain)中的,应该就完全搞明白Spring Security的初始化过程了。
下次分析。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。