SpringSecurity------WebSecurityConfiguration配置类
一、WebSecurityConfiguration是怎样被加载的
二、WebSecurityConfiguration主要做了什么
三、WebSecurityConfiguration的源码分析
1、属性字段
2、核心方法
内部初始化WebSecurity的setFilterChainProxySecurityConfigurer()方法
内部构建FilterChainProxy的springSecurityFilterChain()方法
3、使用@Autowired注入了一些Bean
4、使用@Bean初始化一些Bean
5、实现的接口方法
6、一个内部类
一、WebSecurityConfiguration是怎样被加载的
通过在配置类上加入@EnableWebSecurity注解来引入WebSecurityConfiguration.class配置类,源码如下:

@Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 @Documented
 @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
         HttpSecurityConfiguration.class })
 @EnableGlobalAuthentication
 @Configuration
 public @interface EnableWebSecurity {


我们可以看到在注解@EnableWebSecurity上使用@Import()引入了WebSecurityConfiguration.class配置类。

二、WebSecurityConfiguration主要做了什么
简单的说,这个类的作用就是用来创建FilterChainProxy,FilterChainProxy是一个Servlet Filter,他是一组SecurityFilterChain的代理,用于管理这些SecurityFilterChain

首先,FilterChainProxy是SpringSecurity提供的基于Servlet标准的过滤器,他可以被Servlet容器使用。SecurityFilterChain是SpringSecurity提供的自有安全过滤器链,他不是基于Servlet标准的过滤器。SpringSecurity使用FilterChainProxy管理一组SecurityFilterChain,这样就可以通过代理的方式将SpringSecurity自有的滤器链应用于Servlet容器。

然后,当前配置类会加载容器中所有的WebSecurityConfigurer配置类、WebSecurityCustomizer配置类(5.4以后)、SecurityFilterChain过滤器链。这些都是用于配置生成一个WebSecurity。

接着,当WebSecurity实例被构建完成后,会使用WebSecurity去创建一个FilterChainProxy,这个FilterChainProxy会被放到容器中。

三、WebSecurityConfiguration的源码分析
1、属性字段

//SpringSecurity的FilterChainProxy的建造器
 private WebSecurity webSecurity;
 //标识是否开启debug模式,来自注解@EnableWebSecurity的属性debug
 private Boolean debugEnabled;
 //SpringSecurity的配置类列表
 private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
 //SpringSecurity的核心过滤器链的列表
 private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
 //用户自定义WebSecurity的配置类列表(5.4版本之后新增的配置类)
 private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
 //一个类加载器
 private ClassLoader beanClassLoader;
 //对象后处理器(这里依赖注入的是AutowireBeanFactoryObjectPostProcessor)
 @Autowired(required = false)
 private ObjectPostProcessor<Object> objectObjectPostProcessor;


2、核心方法
内部初始化WebSecurity的setFilterChainProxySecurityConfigurer()方法
在这个方法中会创建一个WebSecurity实例,然后将注解参数列表中@Value()注解引入的所有WebSecurityConfigurer配置设置到WebSecurity实例中。同时初始化了当前配置类的两个属性值webSecurity和webSecurityConfigurers。

@Value()引入方式就是AutowiredWebSecurityConfigurersIgnoreParents的方法调用。

/**
 * 获取并设置容器中已经加载的所有WebSecurityConfigurer实例用于配置,初始化一个WebSecurity
 * 
 * @param objectPostProcessor   后处理对象(AutowireBeanFactoryObjectPostProcessor)
 * @param webSecurityConfigurers 用户自定义的配置(WebSecurityConfigurerAdapter的子类或是WebSecurityConfigurer接口的实现)
 * @throws Exception
 */
 @Autowired(required = false)
 public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
         @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") 
         List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
         throws Exception {
     /**
      * 1、初始化一个WebSecurity实例,并其赋值到类属性webSecurity上
      */
     this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
     /**
      * 2、设置是否开启debug模式
      */
     if (this.debugEnabled != null) {
         this.webSecurity.debug(this.debugEnabled);
     }
     /**
      * 3、根据@Order注解排序,然后检测配置排序是否有重复
      */
     webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
     Integer previousOrder = null;
     Object previousConfig = null;
     for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
         //AnnotationAwareOrderComparator是本类中的一个内部类,下面有介绍
         Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
         if (previousOrder != null && previousOrder.equals(order)) {
             throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order
                     + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
         }
         previousOrder = order;
         previousConfig = config;
     }
     /**
     * 4、将配置添加到webSecurity中
     */
     for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
         this.webSecurity.apply(webSecurityConfigurer);
     }
     /**
     * 5、将配置类列表复制到类属性webSecurityConfigurers上
     */
     this.webSecurityConfigurers = webSecurityConfigurers;


内部构建FilterChainProxy的springSecurityFilterChain()方法
首先,在这个方法中首先会判断是否有用户自定义的WebSecurityConfigurer和SecurityFilterChain:

如果这两种自定义实例同时存在则会抛出异常。
如果只存在SecurityFilterChains,将其设置到已经被创建的webSecurity中。
如果这两个自定义实例都不存在,则会创建一个默认的WebSecurityConfigurerAdapter配置,并将其设置到已经被创建的webSecurity中。
然后,调用webSecurity.build()方法创建一个FilterChainProxy,这个Bean会被放到容器中

/**
  * 创建FilterChainProxy代理
  * 
  * @return
  * @throws Exception
  */
 @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
 public Filter springSecurityFilterChain() throws Exception {
     /**
      * 1、判断是否有自定义配置类
      */
     boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
     /**
      * 2、判断是否有自定义配置的SecurityFilterChain
      */
     boolean hasFilterChain = !this.securityFilterChains.isEmpty();
     /**
      * 3、自定义的WebSecurityConfigurerAdapter和SecurityFilterChain不能同时存在
      */
     Assert.state(!(hasConfigurers && hasFilterChain),
             "Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
     /**
      * 4、如果没有配置类且没有SecurityFilterChain,创建一个默认配置,并添加到webSecurity
      */
     if (!hasConfigurers && !hasFilterChain) {
         WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
                 .postProcess(new WebSecurityConfigurerAdapter() {
             });
         this.webSecurity.apply(adapter);
     }
     /**
      * 5、设置webSecurity的拦截器链和拦截器
      */
     for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
         this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
         for (Filter filter : securityFilterChain.getFilters()) {
             if (filter instanceof FilterSecurityInterceptor) {
                 this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
                 break;
             }
         }
     }
     /**
      * 6、用户的一些自定义配置webSecurity
      */
     for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
         customizer.customize(this.webSecurity);
     }
     /**
      * 7、以上配置完成webSecurity后调用WebSecurity.build()方法创建FilterChainProxy
      */
     return this.webSecurity.build();
 }


FilterChainProxy的创建过程

3、使用@Autowired注入了一些Bean
注入容器中所有用户自定义的WebSecurityCustomizer

/**
 * 注入容器中所有用户自定义的WebSecurityCustomizer,用于自定义WebSecurity
 * 
 * @param webSecurityCustomizers
 */
 @Autowired(required = false)
 void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) {
     webSecurityCustomizers.sort(AnnotationAwareOrderComparator.INSTANCE);
     this.webSecurityCustomizers = webSecurityCustomizers;
 }


注入容器中所有的SecurityFilterChain

/**
 * 依赖注入所有的SecurityFilterChain
 * 
 * @param securityFilterChains
 */
 @Autowired(required = false)
 void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
     securityFilterChains.sort(AnnotationAwareOrderComparator.INSTANCE);
     this.securityFilterChains = securityFilterChains;
 }


4、使用@Bean初始化一些Bean

/**
  * 初始化一个AutowiredWebSecurityConfigurersIgnoreParents实例,用于加载容器中的所有WebSecurityConfigurer实例
  * 
  * @param beanFactory
  * @return
  */
 @Bean
 public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
         ConfigurableListableBeanFactory beanFactory) {
      return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);


/**
  * 一个事件监听器的管理器,用于管理所有的鉴权事件
  * 
  * @return
  */
 @Bean
 public static DelegatingApplicationListener delegatingApplicationListener() {
     return new DelegatingApplicationListener();


/**
  * 权限表达式的支持
  * 
  * @return
  */
 @Bean
 @DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
 public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
     return this.webSecurity.getExpressionHandler();


/**
  * 权限评估器。对于JSP-tag支持是必须的
  * 
  * @return
  */
 @Bean
 @DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
 public WebInvocationPrivilegeEvaluator privilegeEvaluator() {
     return this.webSecurity.getPrivilegeEvaluator();
 }


/**
  * 钩子接口,用于修改BeanFactory
  * 
  * @return
  */
 @Bean
 public static BeanFactoryPostProcessor conversionServicePostProcessor() {
     return new RsaKeyConversionServicePostProcessor();


5、实现的接口方法
这个方法是接口ImportAware的方法,当前配置类是通过@EnableWebSecurity注解上的@Import注解引入的,实现该接口的方法使得当前配置类可以获取到@EnableWebSecurity的debug属性值

/**
  * 获取注解的日志级别并设置(ImportAware接口的方法)
  */
 @Override
 public void setImportMetadata(AnnotationMetadata importMetadata) {
     Map<String, Object> enableWebSecurityAttrMap = importMetadata
             .getAnnotationAttributes(EnableWebSecurity.class.getName());
     AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap);
     this.debugEnabled = enableWebSecurityAttrs.getBoolean("debug");
     if (this.webSecurity != null) {
         this.webSecurity.debug(this.debugEnabled);

 13
 这个接口可以使得当前配置类获取到加载他的类加载器/**
  * 设置类加载器(BeanClassLoaderAware接口的方法)
  */
 @Override
 public void setBeanClassLoader(ClassLoader classLoader) {
     this.beanClassLoader = classLoader;
 }
 1
 2
 3
 4
 5
 6
 7
 6、一个内部类
 用于获取类上的@Order注解,并提供比较的功能/**
  * 获取类上的Order注解的值
  * 
  * @author dongyaowei
  * @date 2020年12月22日
  */
 private static class AnnotationAwareOrderComparator extends OrderComparator {
     private static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
     @Override
     protected int getOrder(Object obj) {
         return lookupOrder(obj);
     }
     private static int lookupOrder(Object obj) {
         if (obj instanceof Ordered) {
             return ((Ordered) obj).getOrder();
         }
         if (obj != null) {
             Class<?> clazz = ((obj instanceof Class) ? (Class<?>) obj : obj.getClass());
             Order order = AnnotationUtils.findAnnotation(clazz, Order.class);
             if (order != null) {
                 return order.value();
             }
         }
         return Ordered.LOWEST_PRECEDENCE;
     }
 }