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

相关文章
|
监控 Dubbo Java
深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理
深入理解Zookeeper系列-2.Zookeeper基本使用和分布式锁原理
207 0
|
前端开发 算法 数据安全/隐私保护
在前端对登录密码进行加密,md5+盐值
在前端对登录密码进行加密,md5+盐值
768 0
|
Java API 数据安全/隐私保护
POI 导出 Excel:字体颜色、行列自适应、锁住、合并单元格……
POI 导出 Excel:字体颜色、行列自适应、锁住、合并单元格……
816 0
POI 导出 Excel:字体颜色、行列自适应、锁住、合并单元格……
|
Android开发 Kotlin
【错误记录】Kotlin 编译报错 ( Type mismatch: inferred type is String? but String was expected )
【错误记录】Kotlin 编译报错 ( Type mismatch: inferred type is String? but String was expected )
3378 0
【错误记录】Kotlin 编译报错 ( Type mismatch: inferred type is String? but String was expected )
springfox-bridge:随心所欲地为非restful接口生成swagger api文档
### 一、引言     目前,利用swagger框架为restful接口编写API文档非常流行,在spring web项目中,利用springfox+swagger更是可以通过注解的方式直接进行API文档的生成,这样开发者在项目开发的同时就直接把文档准备好了,利用springfox的配置,可以在项目启动后直接浏览器访问查看API文档,同时还能
|
消息中间件 JSON Java
RabbitMQ竟然无法反序列化List
最近在接到了一个需求,大概是通过RabbitMq给xx子系统同步用户数据,要提供单个同步和批量同步。内心暗喜这不简单的很嘛。三下五除二就把代码给写完了但是在联调的过程中,遇到了一个比较奇葩的问题。单个用户进行同步时,子系统可以正常消费。然后进行批量同步的时候,子系统报错了。并抛出java.lang.ClassCastException提示 LinkedHashMap cannot xxxx class 。于是负责子系统的哥们笑嘻嘻的(表面笑嘻嘻)走过来对我说,不是约定List 为啥发个Map过来?看到这个错误,着实让我摸不到头脑。顿时一堆疑问用上心头, 为啥单个对象可以,List就不行
RabbitMQ竟然无法反序列化List
|
编解码 Java 对象存储
【java】对URL中的中文和符号进行UrlEncode转码
【java】对URL中的中文和符号进行UrlEncode转码
522 0
|
JSON Java 测试技术
Spring Boot中使用JUnit5进行单元测试
Spring Boot中使用JUnit5进行单元测试
785 0
Spring Boot中使用JUnit5进行单元测试
基于 FFI 的 PyFlink 下一代 Python 运行时介绍
PyFlink 现有的 Python 运行时及基于 JCP 构建的下一代 Python 运行时的架构及优势。
基于 FFI 的 PyFlink 下一代 Python 运行时介绍
|
存储 JSON Java
HttpURLConnection发送中文乱码问题解决
HttpURLConnection发送中文乱码问题解决
385 0

热门文章

最新文章