springSecurty启动流程
首先
EnableWebSecurity
注解导入了
WebSecurityConfiguration
配置类
@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 {}
首先看这个类org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration
代码如下
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
//通过AutowireBeanFactoryObjectPostProcessor将WebSecurity注入到spring容器中
//WebSecurity是AutowireBeanFactoryObjectPostProcessor的代理对象
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
//从spring容器中获得所有配置的WebSecurityConfigurerAdapter的类
//WebSecurityConfigurerAdapter是我们配置的springSecurity要继承的类
//调用他的apply方法
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
//将WebSecurityConfigurerAdapter放到一个集合LinkedHashMap中
webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
代码分析
上面代码会创建一个 AutowireBeanFactoryObjectPostProcessor
的代理类 WebSecurity
WebSecurity
这个类可以向spring容器添加对象,同时还维护着一个LinkedHashMap
用来存储所有的WebSecurityConfigurerAdapter
,WebSecurityConfigurerAdapter
是配置springSecurity要继承的类
接下来看这个类org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration
代码如下
@Bean(name = "springSecurityFilterChain")
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
//通过AutowireBeanFactoryObjectPostProcessor向spring容器注册WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
//调用
return webSecurity.build();
}
代码分析
上面代码会通过AutowireBeanFactoryObjectPostProcessor
向spring容器注册一个对象WebSecurityConfigurerAdapter
,然后将WebSecurityConfigurerAdapter
存储到webSecurity
中,
然后调用webSecurity
的build
方法,执行代码如下
protected final O doBuild() throws Exception {
//configurers 是webSecurity中存储WebSecurityConfigurerAdapter的LinkedHashMap
synchronized (configurers) {
//通过枚举修改状态
buildState = BuildState.INITIALIZING;
//空方法 用于扩展
beforeInit();
//调用configurers集合中所有对象的init方法
//当前集合中只有一个对象 WebSecurityConfigurerAdapter
init();
buildState = BuildState.CONFIGURING;
beforeConfigure();
//调用configurers集合中所有对象的configure方法
configure();
buildState = BuildState.BUILDING;
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
接下来依次分析 init()
、beforeConfigure()
、configure()
、performBuild()
方法,WebSecurityConfigurerAdapter
中
此部分代码比较多分部分析,代码如下
public void init(final WebSecurity web) throws Exception {
//创建一个HttpSecurity
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
//给WebSecurity设置一个拦截器
web.securityInterceptor(securityInterceptor);
});
protected final HttpSecurity getHttp() throws Exception {
//首先创建DefaultAuthenticationEventPublisher对象然后将这个对象添加到spring容器中
//此对象维护着一个exceptionMappings对象,存储异常和ApplicationEvent
DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
.postProcess(new DefaultAuthenticationEventPublisher());
//将eventPublisher给localConfigureAuthenticationBldr代理
//localConfigureAuthenticationBldr 也就是 AuthenticationManagerBuilder对象
localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
AuthenticationManager authenticationManager = authenticationManager();
authenticationBuilder.parentAuthenticationManager(authenticationManager);
authenticationBuilder.authenticationEventPublisher(eventPublisher);
Map<Class<?>, Object> sharedObjects = createSharedObjects();
//创建http对象,其中FilterComparator中存储了32个过滤器
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
if (!disableDefaults) {
// 往HttpSecurity添加一些列的 配置类
//CsrfConfigurer
//ExceptionHandlingConfigurer
//HeadersConfigurer
//SessionManagementConfigurer
//SecurityContextConfigurer
//RequestCacheConfigurer
//AnonymousConfigurer
//ServletApiConfigurer
//DefaultLoginPageConfigurer
//LogoutConfigurer
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<>()).and()
.logout();
ClassLoader classLoader = this.context.getClassLoader();
//添加一些默认配置
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
//添加一些默认配置
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
}
}
//调用自己配置的 configure方法,添加一些Configurer
configure(http);
return http;
}
protected AuthenticationManager authenticationManager() throws Exception {
//这里仅仅用一个标志位不用锁 也不会线程不安全
//因为build 方法中通过
//if(AtomicBoolean.compareAndSet(false, true)){}
if (!authenticationManagerInitialized) {
//调用配置的configure方法
//方法中我们给 provider的 UserDetailsService,passwordEncoder 成员变量赋值
//同时添加DaoAuthenticationConfigurer 对象
configure(localConfigureAuthenticationBldr);
if (disableLocalConfigureAuthenticationBldr) {
//如果我们没有重写configure方法则调用这里逻辑
authenticationManager = authenticationConfiguration
.getAuthenticationManager();
}
else {
//localConfigureAuthenticationBldr 也就是 AuthenticationManagerBuilder对象
//AuthenticationManagerBuilder中的configurers中只有一个对象DaoAuthenticationConfigurer
//调用 DaoAuthenticationConfigurer 的doBuild方法
//方法中会通过包装创建一个ProviderManager
authenticationManager = localConfigureAuthenticationBldr.build();
}
authenticationManagerInitialized = true;
}
return authenticationManager;
}
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
//循环调用所有配置类的方法
//有的configurer中的configure方法会添加拦截器
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
protected Filter performBuild() throws Exception {
Assert.state(
!securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke "
+ WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
//securityFilterChainBuilder中存储所有的 HttpSecurity
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
//在方法中循环遍历所有HttpSecurity中configurers
//configurers 是webSecurity中存储WebSecurityConfigurerAdapter的LinkedHashMap
//调用所有配置类的configurer 的 init configure 方法
//
securityFilterChains.add(securityFilterChainBuilder.build());
}
//通过FilterChainProxy对securityFilterChains进行包装
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
postBuildAction.run();
return result;
}
}
上面代码通过CsrfConfigurer、ExceptionHandlingConfigurer、HeadersConfigurer、SessionManagementConfigurer、SecurityContextConfigurer、RequestCacheConfigurer、AnonymousConfigurer 、ServletApiConfigurer、DefaultLoginPageConfigurer、LogoutConfigurer
等对象的 configure
方法 添加过滤器,我们配置对应的Configurer
对象就能修改过滤器要拦截的内容,过滤器如下
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CsrfFilter
LogoutFilter
MyTokenFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor