SpringSecurity的初始化流程

简介: SpringSecurity的初始化流程

SpringSecurity的初始化流程

初始化从SpringSecurity的自动化配置类开始

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({ SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class,
      SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {

   @Bean
   @ConditionalOnMissingBean(AuthenticationEventPublisher.class)
   public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
      return new DefaultAuthenticationEventPublisher(publisher);
   }

}

WebSecurityEnablerConfiguration是重点

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {

}
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
      SpringWebMvcImportSelector.class,
      OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
   boolean debug() default false;
}

EnableWebSecurity导入了WebSecurityConfiguration,用来配置WebSecurity

EnableGlobalAuthentication注解导入了配置类AuthenticationConfiguration

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}

重点分析这两个配置

WebSecurityConfiguration

WebSecurityConfiguration实现了ImportAware 接口,使用@Import注解在@EnableWebSecurity上导入WebSecurityConfiguration之后,在WebSecurityConfiguration的setImportMetadata方法方便获取到@EnableWebSecurity注解中的属性值。

WebSecurityConfiguration实现了BeanClassLoaderAware 方便获取ClassLoader对象

重点看setFilterChainProxySecurityConfigurer方法:主要是用来构建一个WebSecurity对象,并且加载所有的配置类对象。

@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
      ObjectPostProcessor<Object> objectPostProcessor,
      @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
      throws Exception {
   webSecurity = objectPostProcessor
         .postProcess(new WebSecurity(objectPostProcessor));
   if (debugEnabled != null) {
      webSecurity.debug(debugEnabled);
   }

   webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);

   Integer previousOrder = null;
   Object previousConfig = null;
   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) {
      webSecurity.apply(webSecurityConfigurer);
   }
   this.webSecurityConfigurers = webSecurityConfigurers;
}

手写创建一个WebSecurity,创建出来之后的对象去对象处理后置器中处理,将webSecurity对象注册到Spring容器中。

然后根据每个配置类的@Order注解对webSecurityConfigurations集合中的所有配置类进行排序,因为一个配置类对应一个过滤器链,因为请求到来时需要先和那个过滤器匹配存在优先级问题。

排序后进入for循环,检查是否存在优先级相等问题,如果存在直接抛出异常。最后遍历所有配置类,调用webSecurity.apply方法加到WebSecurity父类中的configs集合中。

有了WebSecurity对象和配置类就可以构建过滤器FilterChainProxy了

springSecurityFilterChain:

@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();
}

先判断webSecurityConfigurers集合中是否存在配置类,如果不存在立马创建一个匿名的WebSecurityConfigurerAdapter,否则直接调用

webSecurity.build()进行构建,对所有的配置类WebSecurityConfigurerAdapter实例进行构建,在WebSecurityConfigurerAdapter的init方法中又完成HttpSecurity的构建,HttpSecurity构建过程中完成局部AuthenticationManager对象和每一个具体过滤器的构建。

AuthenticationConfiguration

导入ObjectPostProcessorConfiguration配置类,具体实现类是AutowireBeanFactoryObjectPostProcessor,将一个对象注册到Spring容器中。

@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {

构建AuthenticationManager

public AuthenticationManager getAuthenticationManager() throws Exception {
   if (this.authenticationManagerInitialized) {
      return this.authenticationManager;
   }
   AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
   if (this.buildingAuthenticationManager.getAndSet(true)) {
      return new AuthenticationManagerDelegator(authBuilder);
   }

   for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
      authBuilder.apply(config);
   }

   authenticationManager = authBuilder.build();

   if (authenticationManager == null) {
      authenticationManager = getAuthenticationManagerBean();
   }

   this.authenticationManagerInitialized = true;
   return authenticationManager;
}

AuthenticationConfiguration作用:

  1. 导入ObjectPostProcessorConfiguration配置类,具体实现类是AutowireBeanFactoryObjectPostProcessor,将一个对象注册到Spring容器中。
  2. 提供全局的AuthenticationManager

如果重写了AuthenticationManagerBuilder的configure方法,全局AuthenticationManager失效,大部分情况下 我们会重写AuthenticationManagerBuilder的configure方法。

相关文章
|
9月前
|
Java Spring 容器
深入Spring原理-4.Aware接口、初始化和销毁执行顺序、Scope域
深入Spring原理-4.Aware接口、初始化和销毁执行顺序、Scope域
175 0
|
1月前
|
存储 前端开发 Java
SpringBoot整合Flowable【05】- 使用流程变量传递业务数据
本文介绍了如何使用Flowable的流程变量来管理绩效流程中的自定义数据。首先回顾了之前的简单绩效流程,指出现有流程缺乏分数输入和保存步骤。接着详细解释了流程变量的定义、分类(运行时变量和历史变量)及类型。通过具体代码示例展示了如何在绩效流程中插入全局和局部流程变量,实现各节点打分并维护分数的功能。最后总结了流程变量的使用场景及其在实际业务中的灵活性,并承诺将持续更新Flowable系列文章,帮助读者更好地理解和应用Flowable。 简要来说,本文通过实例讲解了如何利用Flowable的流程变量功能优化绩效评估流程,确保每个环节都能记录和更新分数,同时提供了全局和局部变量的对比和使用方法。
84 0
|
7月前
|
存储 Java Spring
Spring初始化加速的思路和方案问题之替换默认的Spring Bean初始化逻辑中的问题如何解决
Spring初始化加速的思路和方案问题之替换默认的Spring Bean初始化逻辑中的问题如何解决
|
8月前
|
算法 Java API
在Spring Boot中实现接口签名验证通常涉及以下步骤
在Spring Boot中实现接口签名验证通常涉及以下步骤
588 4
|
8月前
|
消息中间件 XML Java
经验大分享:spring项目在启动的时候执行方法初始化
经验大分享:spring项目在启动的时候执行方法初始化
104 0
|
9月前
|
Java 容器 Spring
SpringBoot:Bean生命周期自定义初始化和销毁
SpringBoot:Bean生命周期自定义初始化和销毁
214 1
|
安全 Java 数据库连接
四.SpringSecurity基础-自定义登录流程
SpringSecurity基础-自定义登录流程
|
9月前
|
Java 数据库
Activity7整合springboot:流程部署,定义,实例(一)
Activity7整合springboot:流程部署,定义,实例(一)
|
Java Spring
spring bean初始化过程
从这个简单的代码衍生,使用AnnotationConfigApplicationContext看一下spring bean的初始化过程
191 0
spring bean初始化过程
|
安全 Java Spring
SpringSecurity 初始化解析
分析知道了SpringSecurity对一个请求的具体处理流程
68 0