接上一篇文章。

我们已经完成了对配置类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。

我们再来回忆一下:
image.png

上图中右半部分的DefaultSecurityFilterChain已经装配好、左边的FilterChainProxy也已经装配好,并且,DefaultSecurityFilterChain的各过滤器已经准备完毕。

万事俱备,只欠东风:FilterChainProxy装配到DeletatingFilterProxy中,然后再研究一下DeletatingFilterProxy是怎么配置到Servlet的过滤器链(FilterChain)中的,应该就完全搞明白Spring Security的初始化过程了。

下次分析。

上一篇 Spring Security的初始化过程(1)
下一篇 Spring Security的初始化过程(3)


45 声望17 粉丝