首页 > 编程语言 >[SpringSecurity5.6.2源码分析四]:WebSecurityConfiguration

[SpringSecurity5.6.2源码分析四]:WebSecurityConfiguration

时间:2023-09-07 18:05:10浏览次数:40  
标签:SpringSecurity5.6 ...... object 源码 result WebSecurityConfiguration new null publ


WebSecurityConfiguration的重点是通过WebSecurity创建FilterChainProxy

  • • 先分析内部的方法

1、elegatingApplicationListener

  • • 看名字就能看出来注册了一个委托类型的监听器
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware { 
   ......
   @Bean
   public static DelegatingApplicationListener delegatingApplicationListener() {
      return new DelegatingApplicationListener();
   }
   ......
}
  • • 内部其实就是一个很简单的把监听器又嵌套了一层,在内部for循环发送事件,所以说重点就是如何注册内部的监听器的
public final class DelegatingApplicationListener implements
      ApplicationListener<ApplicationEvent> {
   private List<SmartApplicationListener> listeners = new CopyOnWriteArrayList<>();

   public void onApplicationEvent(ApplicationEvent event) {
      if (event == null) {
         return;
      }
      for (SmartApplicationListener listener : listeners) {
         Object source = event.getSource();
         if (source != null && listener.supportsEventType(event.getClass())
               && listener.supportsSourceType(source.getClass())) {
            listener.onApplicationEvent(event);
         }
      }
   }

   /**
    * Adds a new SmartApplicationListener to use.
    *
    * @param smartApplicationListener the SmartApplicationListener to use. Cannot be
    * null.
    */
   public void addListener(SmartApplicationListener smartApplicationListener) {
      Assert.notNull(smartApplicationListener,
            "smartApplicationListener cannot be null");
      listeners.add(smartApplicationListener);
   }
}
  • • Debug就会发现默认只有SessionManagementConfigurer会注册一个SessionRegistryImpl
  • • SessionRegistryImpl是针对SpringSecurity内部维护的SessionInformation的操作 比如说用户登录后,才会创建会话session,那么通常会有一个SpringSecurity的SessionInformation的创建

2、setFilterChainProxySecurityConfigurer

  • • 重点就是创建了WebSecurity,并注册对应的配置类
  • • 是创建FilterChainProxy的核心类
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
      @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
      throws Exception {
   this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
   if (this.debugEnabled != null) {
      this.webSecurity.debug(this.debugEnabled);
   }
   //先对配置类进行排序
   webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
   Integer previousOrder = null;
   Object previousConfig = null;
   //这个for循环的意思是:配置类可以通过@Order进行排序,但是如果@Order中的value值相同就表示无法进行排序,就直接抛出异常
   for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
      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;
   }
   for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
      this.webSecurity.apply(webSecurityConfigurer);
   }
   this.webSecurityConfigurers = webSecurityConfigurers;
}
  • • 入参有两个重要的类

2.1 ObjectPostProcessor

  • • ObjectPostProcessor
  • • SecurityConfigurer
  • • 首先这个类有一个重要的实现AutowireBeanFactoryObjectPostProcessor,默认注册到容器的也是这个类
  • • Spring Security会通过new创建很多bean, 为了让这些由SpringSecurity创建的bean也和跟spring容器中的bean有同样的生命周期,所以出现了此类
final class AutowireBeanFactoryObjectPostProcessor
     implements ObjectPostProcessor<Object>, DisposableBean, SmartInitializingSingleton {

  private final Log logger = LogFactory.getLog(getClass());

  private final AutowireCapableBeanFactory autowireBeanFactory;

  private final List<DisposableBean> disposableBeans = new ArrayList<>();

  private final List<SmartInitializingSingleton> smartSingletons = new ArrayList<>();

  AutowireBeanFactoryObjectPostProcessor(AutowireCapableBeanFactory autowireBeanFactory) {
     Assert.notNull(autowireBeanFactory, "autowireBeanFactory cannot be null");
     this.autowireBeanFactory = autowireBeanFactory;
  }

   /**
  * 让这些由SpringSecurity创建的bean也和跟spring容器中的bean有同样的生命周期,也能注入相应的依赖,从而进入准备好被使用的状态
  * @param object the object to initialize
  * @param <T>
  * @return
  @Override
  @SuppressWarnings("unchecked")
  public <T> T postProcess(T object) {
     if (object == null) {
        return null;
     }
     T result = null;
     try {
        //进行初始化
        result = (T) this.autowireBeanFactory.initializeBean(object, object.toString());
     }
     catch (RuntimeException ex) {
        Class<?> type = object.getClass();
        throw new RuntimeException("Could not postProcess " + object + " of type " + type, ex);
     }
     //进行自动装配属性
     this.autowireBeanFactory.autowireBean(object);
     if (result instanceof DisposableBean) {
        this.disposableBeans.add((DisposableBean) result);
     }
     if (result instanceof SmartInitializingSingleton) {
        this.smartSingletons.add((SmartInitializingSingleton) result);
     }
     return result;
  }

  @Override
  public void afterSingletonsInstantiated() {
     for (SmartInitializingSingleton singleton : this.smartSingletons) {
        singleton.afterSingletonsInstantiated();
     }
  }

  @Override
  public void destroy() {
     for (DisposableBean disposable : this.disposableBeans) {
        try {
           disposable.destroy();
        }
        catch (Exception ex) {
           this.logger.error(ex);
        }
     }
  }

}

2.2 SecurityConfigurer

  • • SpringSecurity在创建对应的过滤器的时候是通过建造者模式进行创建的,SecurityConfigurer算是比较顶级的一个类了,较为完整的构建流程如下:
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
      extends AbstractSecurityBuilder<O> {
    ......
    @Override
    protected final O doBuild() throws Exception {
       synchronized (this.configurers) {
          this.buildState = BuildState.INITIALIZING;
          beforeInit();
          init();
          this.buildState = BuildState.CONFIGURING;
          beforeConfigure();
          configure();
          this.buildState = BuildState.BUILDING;
          O result = performBuild();
          this.buildState = BuildState.BUILT;
          return result;
       }
  ......
  • • 完整的走完了beforeInit、init、beforeConfigure、configure、performBuild,也映射出了建造者模式下的构建状态
private enum BuildState {

   /**
    * 表明当前构建器还未进行构建
    */
   UNBUILT(0),

   /**
    * 表明当前构建器正在执行初始化方法,具体规则在doBuild()方法中,下同
    */
   INITIALIZING(1),

   /**
    * 表明当前构建器执行完初始化方法
    */
   CONFIGURING(2),

   /**
    * 表明当前构建器已经执行完配置方法
    */
   BUILDING(3),

   /**
    * 表明当前构建器已经执行完构建方法
    */
   BUILT(4);
}

3、autowiredWebSecurityConfigurersIgnoreParents

  • • 作用是获取容器中的WebSecurityConfigurer
  • • WebSecurityConfigurer的实现类WebSecurityConfigurerAdapter是配置Spring Security过滤器的实现类
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
      extends AbstractSecurityBuilder<O> {
    ......
    @Bean
    public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
          ConfigurableListableBeanFactory beanFactory) {
       return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
    }
  ......

4、setImportMetadata

  • • 本质上就是获取在@EnableWebSecurity中设置的是否开启debug日志打印
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
      extends AbstractSecurityBuilder<O> {
    ......
    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
       //默认只有WebSecurityEnablerConfiguration导入了此类,而此类一定标志了@EnableWebSecurity
       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);
       }
    }
  ......

5、springSecurityFilterChain

  • • 往容器中注册过滤器,是构建过滤器的入口,也就是注册FilterChainProxy
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
      extends AbstractSecurityBuilder<O> {
    ......
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
   boolean hasConfigurers = webSecurityConfigurers != null
         && !webSecurityConfigurers.isEmpty();
   // 当配置类和过滤器链都没有的时候注册一个配置类
   if (!hasConfigurers) {
      WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
            .postProcess(new WebSecurityConfigurerAdapter() {
            });
      webSecurity.apply(adapter);
   }
   return webSecurity.build();
}
  ......
  • • 第六行代码会判断是否有配置类的存在,即使我们没有注册WebSecurityConfigurer的配置类,也依旧会有一个DefaultConfigurerAdapter注册到容器中
graph TD
SecurityAutoConfiguration --> SpringBootWebSecurityConfiguration --> DefaultConfigurerAdapter


标签:SpringSecurity5.6,......,object,源码,result,WebSecurityConfiguration,new,null,publ
From: https://blog.51cto.com/u_14008019/7399366

相关文章

  • 韬客时代卷轴模式系统开发介绍和部分核心源码
    韬客时代是一种卷轴模式系统。什么是卷轴模式呢?新用户注册,先送你一部分积分,该积分用于兑换一个初始任务,俗称卷轴!卷轴模式的赚钱的原理是,你用积分兑换初级任务包,完成卷轴任务之后,你可以获得更多的积分,然后复投,达到一定数量后可以兑换更高级的任务包,任务包越高级每次获得的积分也就越......
  • 抖音小程序源码成品开发
      抖音上的流量现在大部分人都知道,目前用户量达到了8亿多,商家都想在抖音字节平台上开发一个小程序。拥有了这样的小程序就意味着拥有了大把的流量,抖音小程序也属于是新型的渠道,和其他的小程序一样,轻便,高效,无需下载,深受用户的高度关注。  抖音小程序源码如何是完整版的可以......
  • map、sync.map、concurrent-map适用场景与源码解析
    最近一直加班,无论工作日还是周末,虽然每天很忙但总感觉空空的,很少有时间停下来思考与总结。项目中各种甩锅,最后最苦逼的还是落到了研发的头上,文档编写、环境部署、问题排查虐得一遍又一遍。事情杂乱,研发效率超级低,不知道何是是个头呀背景在go中,map是最常用的集合之一。其底层key存......
  • 【错误记录】exe4j 打包程序无法设置 jar 包依赖的问题 ( 将源码 和 依赖库打包到同一
    文章目录一、问题描述二、解决方案一、问题描述在【错误记录】IntelliJIDEA导出可执行jar包执行报错(java.lang.ClassNotFoundException|打包时没有选择依赖库)博客中遇到java.lang.ClassNotFoundException:com.microsoft.sqlserver.jdbc.SQLServerDrivera......
  • Uchardet C++源码编译步骤 文本编码检测命令行工具 Command line
    从官网 https://www.freedesktop.org/wiki/Software/uchardet/下载源码 https://www.freedesktop.org/software/uchardet/releases/=====================================================================================下载编译工具:Cmake和mingw64https://cmake.org......
  • Spring源码分析(十)Spring中Bean的生命周期(下)
    在上篇文章中,写了bean的生命周期的简单介绍,主要介绍了整个生命周期中的初始化阶段以及基于容器启动停止时LifeCycleBean的回调机制。另外对bean的销毁过程也做了简单介绍,但是对于整个bean的生命周期,这还只是一小部分,在这篇文章中,我将继续完成剩下部分的内容,同时对之前的内容做一次......
  • 一套成熟的实验室信息管理系统源码,集前处理、检验、报告、质控、统计分析、两癌等模块
    一套成熟的实验室信息管理系统,集前处理、检验、报告、质控、统计分析、两癌等模块为一体的实验室信息管理系统。在整个检验过程中实时对检验结果监控、评估、分析、统计并对操作规程进行严格规范。它的开发和应用将加快检验科管理的统一化、网络化、标准化的进程。技术架构:ASP.NET......
  • 直播系统源码,系统分析篇:不可或缺的云转码系统
    科技的进步发展让人们的生活越来越便利,而当今社会我们最常使用让我们生活变得更便利的方式,就是下载适合我们解决困难的相关直播系统源码搭建出来的APP,在一个完整的APP内,有着多种的功能强大的系统,从这篇文章开始,我就为大家一一介绍这些系统,今天我们先介绍第一个系统:云转码系统。云转......
  • 全新二开游戏支付通道/话费/电网、抖音、快手、紫水晶带云端源码
    更新日志2021-12-29优化抖音通道更新剑网三金山版通道2021-12-27新增LOL手游(微信H5)新增来疯星币(双端H5)修复YY紫宝石通道修复YY金钻通道2021-12-25更新联通话费通道新增花椒双端H5通道更新虎牙通道更新腾讯系列通道2021-12-12更新YY金钻通道新增YY紫宝石通道(双端H5)2021-12......
  • 淘宝客APP源码社交电商uniapp开发源码前端源码自营商城
    需要一定基础,小白慎入。这套程序一个用户花了3000大洋买的,里面看了大致的功能,因为只是搭建看的后台,所以不是很标准,感兴趣的可以自行研究:    压缩包:材料自取,提取码:ffkx1.首页基础装修2.丰富选品库3.淘口令解析4.支持京东5.支持淘宝6.支持聚划算7.三级返利8.支持拼......