前言
在了解Spring Security初始化过程,可以先了解一下spring bean的生命周期,以及springboot的自动装配原理。
Spring Security的初始化过程是一个复杂但有序的过程,它主要依赖于Spring框架的自动配置机制以及开发者提供的配置信息。以下是从注解方式(Java Configuration)的角度来概述Spring Security在Spring Boot项目中的初始化过程
1. 自动配置类
在Spring Boot项目中,Spring Security的初始化通常是通过自动配置类(Auto-configuration classes)来实现的。这些自动配置类会根据项目中的依赖和配置来决定是否启用以及如何配置Spring Security。主要涉及的自动配置类包括SecurityAutoConfiguration(在springboot的自动装配包的imports文件可以找到)、SpringBootWebSecurityConfiguration等。
SecurityAutoConfiguration
通过代码可以看到,该类引入了SpringBootWebSecurityConfiguration
@AutoConfiguration(before = UserDetailsServiceAutoConfiguration.class)
@ConditionalOnClass(DefaultAuthenticationEventPublisher.class)
@EnableConfigurationProperties(SecurityProperties.class)
@Import({ SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class })
public class SecurityAutoConfiguration {
@Bean
@ConditionalOnMissingBean(AuthenticationEventPublisher.class)
public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
return new DefaultAuthenticationEventPublisher(publisher);
}
}
SpringBootWebSecurityConfiguration
/**
* Adds the {@link EnableWebSecurity @EnableWebSecurity} annotation if Spring Security
* is on the classpath. This will make sure that the annotation is present with
* default security auto-configuration and also if the user adds custom security and
* forgets to add the annotation. If {@link EnableWebSecurity @EnableWebSecurity} has
* already been added or if a bean with name
* {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been configured by the user, this
* will back-off.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnClass(EnableWebSecurity.class)
@EnableWebSecurity
static class WebSecurityEnablerConfiguration {
}
@EnableWebSecurity
@EnableWebSecurity表示启用Spring Security。这个注解是初始化Spring Security的入口点,它会触发一系列的自动配置过程。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
public @interface EnableWebSecurity {
/**
* Controls debugging support for Spring Security. Default is false.
* @return if true, enables debug support with Spring Security
*/
boolean debug() default false;
}
核心在于引入了({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
WebSecurityConfiguration
spring security框架有三个核心
- 整个框架的核心是一个过滤器,这个过滤器名字叫springSecurityFilterChain类型是FilterChainProxy
- 核心过滤器里面是过滤器链(列表),过滤器链的每个元素都是一组URL对应一组过滤器
- WebSecurity用来创建FilterChainProxy过滤器,HttpSecurity用来创建过滤器链的每个元素。
而这个三个核心的创建过程,我们也能在WebSecurityConfiguration中看到
参考:初始化过程
创建WebSecurity
/**
* Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>}
* instances used to create the web configuration.
* @param objectPostProcessor the {@link ObjectPostProcessor} used to create a
* {@link WebSecurity} instance
* @param beanFactory the bean factory to use to retrieve the relevant
* {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>} instances used to
* create the web configuration
* @throws Exception
*/
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
ConfigurableListableBeanFactory beanFactory) throws Exception {
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled);
}
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new AutowiredWebSecurityConfigurersIgnoreParents(
beanFactory)
.getWebSecurityConfigurers();
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) {
this.webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
-
该方法负责收集配置类对象列表webSecurityConfigurers,方法执行时会先得到webSecurityConfigurers并排序(所有实现了WebSecurityConfigurerAdapter的配置类实例)并创建WebSecurity,WebSecurity是通过直接new的方式手动创建,并利用objectPostProcessor的实现AutowireBeanFactoryObjectPostProcessor注入spring 容器进行管理;
-
通过AutowiredWebSecurityConfigurersIgnoreParents的getWebSecurityConfigurers()方法,获取所有实现WebSecurityConfigurer的配置类,并管理在map中
-
关于objectPostProcessor,该类可以实现spring bean的手动装配
参考:objectPostProcessor
参考2
调用springSecurityFilterChain创建过滤器链
WebSecurity是一个建造者,所以我们去看这些方法build(); doBuild(); init(); configure(); performBuild();
build()方法定义在WebSecurity对象的父类AbstractSecurityBuilder中,调用的AbstractConfiguredSecurityBuilder#doBuild()
doBuild()先调用init();configure();等方法
doBuild()最后调用了WebSecurity对象的perfomBuild(),来创建了FilterChainProxy对象,performBuild()里遍历securityFilterChainBuilders建造者列表,把每个SecurityBuilder建造者对象构建成SecurityFilterChain实例,最后创建并返回FilterChainProxy。
参考:参考1