Spring Security原理篇(二) 过滤器原理

上篇文章通过对WebSecurityConfiguration这个配置类的源码阅读,已经了解到,在启动的时候主要创建了两个对象,WebSecurity和名字为springSecurityFilterChainFilter。这篇文章主要是通过源码阅读,查看一下Filter的创建过程,以及后面的工作原理。

1. Filter的创建

1.1再看Filter的创建

/**
     * Creates the Spring Security Filter Chain
     * @return the {@link Filter} that represents the security filter chain
     * @throws Exception
     */
    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
        //T1 查看是否有WebSecurityConfigurer的相关配置
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();
        //T2 如果没有,说明我们没有注入继承WebSecurityConfigurerAdapter 的对象
        if (!hasConfigurers) {
                        
            //T3 创建默认的配置信息WebSecurityConfigurerAdapter ,保证Spring Security的最基础的功能,如果我们要有自定义的相关,一定要重写配置
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            //T4 默认配置信息载入webSecurity
            webSecurity.apply(adapter);
        }
        // T5这里build一个Filter
        return webSecurity.build();
    }
  • T1,T2,T3,T4处的代码请查看代码的注释,这里重点讲解T5处的代码
  • webSecurity对象在此时已经加载完所有的配置
  • webSecurity对象为我们创建一个Filter通过的是build()方法

1.2 WebSecuritybuild()方法

  • WebSecurity继承了AbstractConfiguredSecurityBuilder类,实现了SecurityBuilder接口.事实上AbstractConfiguredSecurityBuilder类也是实现了SecurityBuilder接口。子类和父类实现同一个接口。事实上是为了子类在反射调用方法getInterfaces()中可以获取到接口,根据这里的情况就是WebSecurity反射调用getInterfaces()可以获取到SecurityBuilder接口(个人理解,也许编写者是另有深意)。

  • WebSecurity的继承关系,了解继承关系,对于后面的代码的理解大有好处

    WebSecurity类图

  • SecurityBuilder定义了构建的接口标准

  • AbstractSecurityBuilder实现build方法,用AtomicBoolean的变量building保证多线程情况下,操作的原子性。此处采用的是模板模式。定义了doBuild()抽象方法

  • AbstractConfiguredSecurityBuilder 继承AbstractSecurityBuilder实现doBuild()方法,也采用模板模式,定义了实现的具体的步骤,如UNBUILTINITIALIZING,CONFIGURING,BUILDING,以及BUILT

1.2.1 SecurityBuilder接口定义

public interface SecurityBuilder {

    /**
     *
     * Builds the object and returns it or null.
     * @return the Object to be built or null if the implementation allows it.
     * @throws Exception
     *
     */
    O build() throws Exception;
}
  • 该接口的作用是定义一个构建的对象标准
  • 只定义了build()方法,返回值是一个泛型
  • 我们看一下WebSecurity的定义
public final class WebSecurity extends
        AbstractConfiguredSecurityBuilder implements
        SecurityBuilder, ApplicationContextAware {
        ...
        ...
}
  • 从上面的代码可以看出WebSecurity指定泛型的类型为Filter,结合上面接口build()方法我们可以知道,WebSecuritybuild()方法返回的是一个Filter,Spring Securiy 通过这个来创建一个过滤器

1.2.2 WebSecuritybuild()过程

  • 从上面WebSecurity的类图来看,AbstractSecurityBuilder保证了线程的安全,AbstractConfiguredSecurityBuilder保证了构建过程以及构建状态。WebSecurity通过performBuild()来实现自身的构建
  • AbstractConfiguredSecurityBuilder的构建过程,我们看一下doBuild()方法的定义
@Override
    protected final O doBuild() throws Exception {
        synchronized (configurers) {
            buildState = BuildState.INITIALIZING;
            beforeInit(); //默认什么都没做,WebSecurity也没有重写
            init(); //T1 默认此处调用WebSecurityConfigurerAdapter的init(final WebSecurity web)方法
            buildState = BuildState.CONFIGURING;

            beforeConfigure(); //默认什么都不做,WebSecurity没有重写
            configure();//调用WebSecurityConfigurerAdapter的configure(WebSecurity web),但是什么都没做

            buildState = BuildState.BUILDING;

            O result = performBuild(); //T2这里调用WebSecurity的performBuild()方法

            buildState = BuildState.BUILT;

            return result; //从WebSecurity的实现,这里返回了一个Filter,完成构建过程
        }
    }
  • T1处调用WebSecurityConfigurerAdapter的init(final WebSecurity web)方法,看一下源代码的定义
    /**
     * @param web
     * @throws Exception
     */
    public void init(final WebSecurity web) throws Exception {
        //构建HttpSecurity对象
        final HttpSecurity http = getHttp();
        web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
            public void run() {
                FilterSecurityInterceptor securityInterceptor = http
                        .getSharedObject(FilterSecurityInterceptor.class);
                web.securityInterceptor(securityInterceptor);
            }
        });
    }

这里构建了HttpSecurity对象,以及有一个共享对象FilterSecurityInterceptor ,我们还是要将完整的流程讲完,在下一篇文章对HttpSecurity对象做专门的解读,因为这个HttpSecurity对象扮演者非常重要的角色

  • T2 , 根据WebSecurity的属性构建Filter的performBuild()方法
@Override
    protected Filter performBuild() throws Exception {
        Assert.state(
                //T1  securityFilterChainBuilders哪里来的?
                !securityFilterChainBuilders.isEmpty(),
                () -> "At least one SecurityBuilder needs to be specified. "
                        + "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
                        + "More advanced users can invoke "
                        + WebSecurity.class.getSimpleName()
                        + ".addSecurityFilterChainBuilder directly");
               //T2 ignoredRequests.size()到底是什么?
        int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
                //这个securityFilterChains 的集合里面存放的就是我们所有的过滤器链,根据长度的定义,我们也可以知道分为两种一个是通过ignoredRequests来的过滤器链,一个是通过securityFilterChainBuilders这个过滤器链构建链来的。
        List securityFilterChains = new ArrayList<>(
                chainSize);

                //如果是ignoredRequest类型的,那么久添加默认过滤器链(DefaultSecurityFilterChain)
        for (RequestMatcher ignoredRequest : ignoredRequests) {
            securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
        }
               
                //如果是securityFilterChainBuilder类型的,那么通过securityFilterChainBuilder的build()方法来构建过滤器链
        for (SecurityBuilder securityFilterChainBuilder : securityFilterChainBuilders) {
            securityFilterChains.add(securityFilterChainBuilder.build());
        }
               
            //将过滤器链交给一个过滤器链代理对象,而这个代理对象就是返回回去的过滤器,后面的代码先不做交代。到这里为止,过滤器的过程已经结束
             //T3 什么是FilterChainProxy? 
        FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
        if (httpFirewall != null) {
            filterChainProxy.setFirewall(httpFirewall);
        }
        filterChainProxy.afterPropertiesSet();

        Filter result = filterChainProxy;
        if (debugEnabled) {
            logger.warn("\n\n"
                    + "********************************************************************\n"
                    + "**********        Security debugging is enabled.       *************\n"
                    + "**********    This may include sensitive information.  *************\n"
                    + "**********      Do not use in a production system!     *************\n"
                    + "********************************************************************\n\n");
            result = new DebugFilter(filterChainProxy);
        }
        postBuildAction.run();
        return result;
    }

从上面源码和标注的注释(也许理解不透彻)来看,其实我们只要回答清楚上面的T1,T2,T3这三个问题,就基本弄清楚了。

1.2.3 WebSecuritysecurityFilterChainBuilders属性哪里来的

  • 我们在上面说到AbstractConfiguredSecurityBuilderdoBuild()里面的init()方法实际上调用的是WebSecurityConfigurerAdapter的init(final WebSecurity web)方法,前面没有详细解释,这里再次引入源码
       /**
     * @param web
     * @throws Exception
     */
    public void init(final WebSecurity web) throws Exception {
        final HttpSecurity http = getHttp();
               
                //T1
        web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
            public void run() {
                FilterSecurityInterceptor securityInterceptor = http
                        .getSharedObject(FilterSecurityInterceptor.class);
                web.securityInterceptor(securityInterceptor);
            }
        });
    }
  • T1处调用了WebSecurityaddSecurityFilterChainBuilder()方法,我们看一下这个方法的源代码
public WebSecurity addSecurityFilterChainBuilder(
            SecurityBuilder securityFilterChainBuilder) {
                 //这个就是securityFilterChainBuilders变量
        this.securityFilterChainBuilders.add(securityFilterChainBuilder);
        return this;
    }
  • 从上面两处代码中我们似乎已经知道,在构建Filter过程的初始化的时候,我们对securityFilterChainBuilders这个变量进行了赋值,默认情况下securityFilterChainBuilders里面只有一个对象,那就是HttpSecurity

1.2.4 ignoredRequests到底是什么

  • 其实这个非常简单ignoredRequests只是WebSecurity的一个属性
  • ignoredRequests的list中的值从哪里来的呢,其实我们可以看到里面有一个ignore()方法,通过这个来进行设置的
  • 怎么设置呢,那我们得看看WebSecurityConfigurerAdapter这个类了,里面有一个configure方法供我们重写
public void configure(WebSecurity web) throws Exception {
}
  • 具体的例子如下
@Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
        web.ignoring()
           .mvcMatchers("/favicon.ico", "/webjars/**", "/css/**");
    }

  • 然后值得一提的是这里有多少个mvcMatchers就会创建多少个ignoredRequests的对象,也就会有多少个过滤器链,至于源码,可以自行阅读,也是在WebSecurity里面定义的内部类IgnoredRequestConfigurer这个类里面

1.2.5 FilterChainProxy到底是什么

  • 上面的描述中我们知道, FilterChainProxy是真正返回的Filter,上面代码中 FilterChainProxy的对象创建的源码为:
 FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
  • 然后这个FilterChainProxy又是比较复杂的玩意儿,我们还是在接下来文章继续吧。

1.3 过滤器实现的流程

  • 虽然到目前为止,整个还是没有交代清楚,但是我们还是需要画一个小图来整理一下前面的流程吧。为接下来HttpSecurityFilterChainProxy类解读做点准备
Filter创建过程.png

我们暂时的放过一下FilterChainProxy,下一篇我们继续HttpSecurity

你可能感兴趣的:(Spring Security原理篇(二) 过滤器原理)