写点什么

SpringSecurity 的初始化流程

作者:周杰伦本人
  • 2022 年 7 月 01 日
  • 本文字数:3176 字

    阅读完需:约 10 分钟

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)@EnableWebSecuritypublic 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@Configurationpublic @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)@Configurationpublic @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 方法。

发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2020.02.29 加入

公众号《盼盼小课堂》,多平台优质博主

评论

发布
暂无评论
SpringSecurity的初始化流程_7月月更_周杰伦本人_InfoQ写作社区