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 作用:
导入 ObjectPostProcessorConfiguration 配置类,具体实现类是 AutowireBeanFactoryObjectPostProcessor,将一个对象注册到 Spring 容器中。
提供全局的 AuthenticationManager
如果重写了 AuthenticationManagerBuilder 的 configure 方法,全局 AuthenticationManager 失效,大部分情况下 我们会重写 AuthenticationManagerBuilder 的 configure 方法。
评论