在 SpringBoot - 简单集成 SpringSecurity 这篇文章中,我们知道只要在配置类上加上 @EnableWebSecurity
注解,就可以使我们的应用有一个默认配置的安全校验。接下我们就以 @EnableWebSecurity
为入口跟踪一下 Spring
在底层为我们做了哪些工作。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, HttpSecurityConfiguration.class})
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
@EnableWebSecurity
使我们拥有了SpringSecurity
的能力,并为IoC 容器
中导入了几个配置类,比较重要的一个配置是:WebSecurityConfiguration
,我们来看一下WebSecurityConfiguration
为我们做了哪些工作
这里忽略了一些非主流程的代码,我们只需要关心重要流程
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
// 在 setFilterChainProxySecurityConfigurer 方法中初始化
private WebSecurity webSecurity;
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private List<SecurityFilterChain> securityFilterChains = Collections.emptyList();
private List<WebSecurityCustomizer> webSecurityCustomizers = Collections.emptyList();
private ClassLoader beanClassLoader;
@Autowired(required = false)
private ObjectPostProcessor<Object> objectObjectPostProcessor;
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
return this.webSecurity.getExpressionHandler();
}
/**
* Creates the Spring Security Filter Chain
* @return the {@link Filter} that represents the security filter chain
* @throws Exception
*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
// 如果我们自定义了配置类,这里就为 true
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
// 默认 securityFilterChain 为空,所以这里为 false
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
Assert.state(!(hasConfigurers && hasFilterChain),
"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
if (!hasConfigurers && !hasFilterChain) {
WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break;
}
}
}
// WebSecurity 的一些自定义配置
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
// 最后调用 WebSecurity 的 build 方法(重点)!!!
// 整篇文章都在讲这个 build 方法,截止到文章末尾,这个方法也就走完了
return this.webSecurity.build();
}
// 设置实例的 WebSecurity 属性,以及 webSecurityConfigurers
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
// 获取 WebSecurityConfigurers,配置类集合
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
// 先创建一个 WebSecurity 对象
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled);
}
// 对配置类集合进行排序
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
...
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
// 将配置类中的信息加入到 WebSecurity 中
this.webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
// 这里的 securityFilterChains 为 null
@Autowired(required = false)
void setFilterChains(List<SecurityFilterChain> securityFilterChains) {
// 设置 securityFilterChains 属性
this.securityFilterChains = securityFilterChains;
}
// 这里的 webSecurityCustomizers 也为 null
@Autowired(required = false)
void setWebSecurityCustomizers(List<WebSecurityCustomizer> webSecurityCustomizers) {
this.webSecurityCustomizers = webSecurityCustomizers;
}
// 获取配置类集合:WebSecurityConfigurers
@Bean
public static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
// 这里会自动注入:ConfigurableListableBeanFactory
ConfigurableListableBeanFactory beanFactory) {
return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
}
...
}
我们首先查看一下
AutowiredWebSecurityConfigurersIgnoreParents
类
public final class AutowiredWebSecurityConfigurersIgnoreParents {
private final ConfigurableListableBeanFactory beanFactory;
AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "beanFactory cannot be null");
this.beanFactory = beanFactory;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
// 获取容器中类型为:WebSecurityConfigurer 的 Bean
Map<String, WebSecurityConfigurer> beansOfType = this.beanFactory.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
}
通过 Debug 可以看到,getWebSecurityConfigurers
方法返回的就是我们继承自 WebSecurityConfigurerAdapter
的自定义配置类。
核心流程 是
WebSecurityConfiguration
中的springSecurityFilterChain()
方法,创建了一个名为springSecurityFilterChain
的 Bean,同时如果我们没有自定义配置的话,会初始化一个WebSecurityConfigurerAdapter
作为WebSecurity
。
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
Assert.state(!(hasConfigurers && hasFilterChain),
"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
if (!hasConfigurers && !hasFilterChain) {
// 没有自定义配置类的话,会初始化一个 WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
...
// 核心流程,返回一个 Filter
return this.webSecurity.build();
}
接下来会调用 WebSecurity
的 build()
方法,来建立一个 Filter
对象对我们的请求进行拦截,从 Spring 官方文档 中我们知道,这里的 Filter
并不是 Servlet
中一个普通的 Filter
这么简单,这个 Filter
是一个代理的 Filter
(DelegatingFilterProxy
),里面还会有过滤器链(SecurityFilterChain
)
在查看 WebSecurity
中的 build
方法之前,我们先来看一下 apply
方法,入参在没有自定义配置的时候是 WebSecurityConfigurerAdapter
:
// AbstractConfiguredSecurityBuilder
public <C extends SecurityConfigurer<O, B>> C apply(C configurer) throws Exception {
add(configurer);
return configurer;
}
private <C extends SecurityConfigurer<O, B>> void add(C configurer) {
Assert.notNull(configurer, "configurer cannot be null");
Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer
.getClass();
synchronized (this.configurers) {
if (this.buildState.isConfigured()) {
throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
}
List<SecurityConfigurer<O, B>> configs = null;
if (this.allowConfigurersOfSameType) {
configs = this.configurers.get(clazz);
}
configs = (configs != null) ? configs : new ArrayList<>(1);
configs.add(configurer);
// 保存配置类集合
this.configurers.put(clazz, configs);
if (this.buildState.isInitializing()) {
this.configurersAddedInInitializing.add(configurer);
}
}
}
WebSecurity
的 build()
方法:
@Override
public final O build() throws Exception {
if (this.building.compareAndSet(false, true)) {
this.object = doBuild();
return this.object;
}
throw new AlreadyBuiltException("This object has already been built");
}
// 由子类实现
protected abstract O doBuild() throws Exception;
// AbstractConfiguredSecurityBuilder
// 第一次进入这个方法,`this.configurers` 应该是我们自定义的配置类,如果没有自定义配置类,那应该是 `WebSecurityConfigurerAdapter`
@Override
protected final O doBuild() throws Exception {
synchronized (this.configurers) {
this.buildState = BuildState.INITIALIZING;
beforeInit();
// 核心流程1
init();
this.buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
this.buildState = BuildState.BUILDING;
// 核心流程2
O result = performBuild();
this.buildState = BuildState.BUILT;
return result;
}
}
// init() 方法调用的是自定义配置类的 init() 方法
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
// 核心流程,这里的 init 方法,走的是 WebSecurityConfigurerAdapter 中的 init 方法
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : this.configurersAddedInInitializing) {
configurer.init((B) this);
}
}
protected abstract O performBuild() throws Exception;
@Override
protected Filter performBuild() throws Exception {
// 这里的 securityFilterChainBuilders 那里来的,还不能为空?
Assert.state(!this.securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder extends SecurityFilterChain> needs to be specified. "
+ "Typically this is done by exposing a SecurityFilterChain bean "
+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
for (RequestMatcher ignoredRequest : this.ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
// 这里的 securityFilterChainBuilders 经过上面的 init 方法之后,里面是一个 HttpSecurity
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {
// 这里通过 HttpSecurity 的 build 方法,转换为了 SecurityFilterChain,在源码中可以看到 build 方法最终返回的是 DefaultSecurityFilterChain
securityFilterChains.add(securityFilterChainBuilder.build());
}
// 把上面收集到的 securityFilterChains 赋值给 FilterChainProxy
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (this.httpFirewall != null) {
filterChainProxy.setFirewall(this.httpFirewall);
}
if (this.requestRejectedHandler != null) {
filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (this.debugEnabled) {
this.logger.warn("\n\n" + "********************************************************************\n"
+ "********** Security debugging is enabled. *************\n"
+ "********** This may include sensitive information. *************\n"
+ "********** Do not use in a production system! *************\n"
+ "********************************************************************\n\n");
result = new DebugFilter(filterChainProxy);
}
this.postBuildAction.run();
return result;
}
这里保留一个疑问:
performBuild()
方法中securityFilterChainBuilders
哪里来的?
WebSecurity
中的 build()
方法会调用 WebSecurityConfigurerAdapter
类的 init()
方法:
@Override
public void init(WebSecurity web) throws Exception {
// 获取 HttpSecurity
HttpSecurity http = getHttp();
// 核心流程 addSecurityFilterChainBuilder,就是把 HttpSecurity 给添加到了 WebSecurity 的 securityFilterChainBuilder 属性中
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
});
}
通过 getHttp()
方法获取到 HttpSecurity
对象之后,使用 addSecurityFilterChainBuilder
对 WebSecurity
中的 securityFilterChainBuilders
变量进行了赋值,在 WebSecurity
中的 performBuild()
方法中又把这个 securityFilterChainBuilders
转换为了 FilterChainProxy
,从这里知道,我们会在 HttpSecurity
中组合 Filter
s。
// WebSecurity
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
到目前为止,虽然还没有把整个的流程给分析完,但是已经基本上把前期的准备工作,和一些 Bean
的创建以及关联说了一下,整个过程如下面的流程图:
下篇文章: SpringSecurity - 启动流程分析(二)