上篇回顾

  • 框架的核心是一个过滤器,这个过滤器名字springSecurityFilterChain类型FilterChainProxy
  • WebSecurityHttpSecurity都是建造者
  • WebSecurity构建目标是FilterChainProxy对象
  • HttpSecurity的构建目标仅仅是FilterChainProxy中的一个SecurityFilterChain
  • @EnableWebSecurity注解,导入了WebSecurityConfiguration
  • WebSecurityConfiguration中创建了建造者对象WebSecurity,和核心过滤器FilterChainProxy

WebSecurityConfiguration开始

WebSecurityConfiguration中需要关注两个方法:

  1. setFilterChainProxySecurityConfigurer()
    

    方法

    创建了WebSecurity建造者对象,用于后面建造FilterChainProxy过滤器

  2. springSecurityFilterChain()
    

    方法

    调用WebSecurity.build(),建造出FilterChainProxy过滤器对象

WebSecurity的创建过程:setFilterChainProxySecurityConfigurer()方法

该方法负责收集配置类对象列表webSecurityConfigurers,并创建WebSecurity

  1. @Value(“#{}”) 是SpEl表达式通常用来获取bean的属性或者调用bean的某个方法。

  2. 方法执行时,会先得到webSecurityConfigurers并排序(所有实现了WebSecurityConfigurerAdapter的配置类实例)

  3. newwebsecurity对象,并使用Spring的容器工具初始化

  4. 判断webSecurityConfigurers内元素的@Order是否有相同,相同的order会抛异常。

    默认order等于LOWEST_PRECEDENCE = 2147483647(参考Integer order = AnnotationAwareOrderComparator.lookupOrder(config)

  5. WebSecurityConfigurerAdapter的子类apply()放入websecurityList<SecurityConfigurer<O, B>> configurersAddedInInitializing中。

setFilterChainProxySecurityConfigurer()

下图是通过AutowiredWebSecurityConfigurersIgnoreParentsgetWebSecurityConfigurers()方法,获取所有实现WebSecurityConfigurer的配置类

getWebSecurityConfigurers

FilterChainProxy的创建过程:springSecurityFilterChain()方法

springSecurityFilterChain()方法中调用webSecurity.build()创建了FilterChainProxy

PS:根据下面代码,我们可以知道如果创建的MySecurityConfig类没有被sping扫描到,

框架会新new 出一个WebSecurityConfigureAdapter对象,这会导致我们配置的用户名和密码失效。

springSecurityFilterChain
springSecurityFilterChain()

我们继续看FilterChainProxy的创建过程:

WebSecurity`是一个建造者,所以我们去看这些方法`build(); doBuild(); init(); configure(); performBuild();

build()方法定义在WebSecurity对象的父类AbstractSecurityBuilder中:

AbstractSecurityBuilder#build()

build()方法会调用WebSecurity对象的父类AbstractConfiguredSecurityBuilder#doBuild()

AbstractConfiguredSecurityBuilder#doBuild()

doBuild()先调用init();configure();等方法

我们上面已经得知了configurersAddedInInitializing里是所有的配置类对象

如下图,这里会依次执行配置类的configure();init()方法

img

这里的 this.configurers就是前面webSecurity.apply(webSecurityConfigurer);注入的webSecurityConfigurer

doBuild()最后调用了WebSecurity对象的perfomBuild(),来创建了FilterChainProxy对象

performBuild()里遍历securityFilterChainBuilders建造者列表

把每个SecurityBuilder建造者对象构建成SecurityFilterChain实例

最后创建并返回FilterChainProxy

performBuild()

securityFilterChainBuilders建造者列表是什么时候初始化的呢

这时候要注意到WebSecurityConfigurerAdapter,这个类的创建了HttpSecurity并放入了securityFilterChainBuilders

securityFilterChainBuilders

WebSecurityConfigurerAdapter是一个安全配置器,我们知道建造者在performBuild()之前都会把循环调用安全配置器init();configure();方法,然后创建HttpSecurity并放入自己的securityFilterChainBuilders里。

  • init()方法传入 WebSecurity init()方法有调用getHttp() ,getHttp()里面调用configure(HttpSecurity http)

    父类中有默认的时效方法,所以你不覆盖就会有默认的认证方式

    protected void configure(HttpSecurity http) throws Exception {
        logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
    
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin().and()
            .httpBasic();
    }
    
  • AbstractConfiguredSecurityBuilder 中调用configure()
    configurer.configure((B) this);
    

    将 WebSecurity 传入 WebSecurityConfigurerAdapterconfigure(WebSecurity http)方法

PS: 前面已经提到了,在WebSecurity初始化时,会依次将WebSecurityConfigurerAdapter的子类放入WebSecurity

public abstract class WebSecurityConfigurerAdapter implements
        WebSecurityConfigurer<WebSecurity> {
}
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends
        SecurityConfigurer<Filter, T> {
}