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方法。

相关文章
|
7月前
|
Java 数据库
SpringBoot手动取消接口执行方案
实际开发中经常会遇到比较耗时的接口操作,但页面强制刷新或主动取消接口调用后后台还是会继续运行,特别是有大量数据库操作时会增加服务器压力,所以进行研究测试后总结了一套主动取消接口调用的解决方案
106 0
|
7月前
|
Java Spring 容器
深入Spring原理-4.Aware接口、初始化和销毁执行顺序、Scope域
深入Spring原理-4.Aware接口、初始化和销毁执行顺序、Scope域
146 0
|
7月前
|
设计模式 Java 机器人
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
SpringBoot3自动配置流程 SPI机制 核心注解 自定义starter
|
6月前
|
Java 数据安全/隐私保护 Spring
SpringSecurity6从入门到实战之默认用户的生成流程
该文档介绍了SpringSecurity6中默认用户的生成流程。在`SecurityAutoConfiguration`源码中,通过`SecurityProperties`配置类,系统默认创建了一个名为&quot;user&quot;的用户,其密码是一个随机生成的UUID。这个用户是在没有在`application.properties`中设置相关配置时自动创建的。
|
7月前
|
移动开发 前端开发
基于Jeecg-boot的flowable流程支持拒绝同意流程操作
基于Jeecg-boot的flowable流程支持拒绝同意流程操作
213 0
|
7月前
|
移动开发 前端开发
基于Jeecg-boot的flowable流程支持拒绝同意流程操作(二)
基于Jeecg-boot的flowable流程支持拒绝同意流程操作(二)
157 0
|
6月前
|
算法 Java API
在Spring Boot中实现接口签名验证通常涉及以下步骤
在Spring Boot中实现接口签名验证通常涉及以下步骤
514 4
|
安全 Java 数据库
SpringSecurity-4-认证流程源码解析
SpringSecurity-4-认证流程源码解析
81 0
|
安全
springsecurity配置类以及授权逻辑的编写
springsecurity配置类以及授权逻辑的编写
105 0
|
安全 Java 数据库连接
四.SpringSecurity基础-自定义登录流程
SpringSecurity基础-自定义登录流程