从Spring Security解析一:安全配置过程概览章节我们知道了springSecurityFilterChain的大致构建过程,这里进步探讨其创建的细节。
springSecurityFilterChain的创建是关键,当创建完该Bean以后,再结合SpringBoot的自动化装配过程完成了在Servlet容器中注册,从而达到了对请求的拦截处理。
WebSecurity的作用就是构建springSecurityFilterChain,通过前面过程的配置,最后执行其buid()方法完成了构建过程。WebSecurity的继承关系如下:
WebSecurityConfiguration中完成springSecurityFilterChain的构建,如下所示:
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
//收集保存所有的SecurityConfigurer配置
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
/**
* Creates the Spring Security Filter Chain
*【默认的Filter的名称为springSecurityFilterChain】
* 注意:在SpringBoot中通过自动化配置会通过该名称来创建DelegatingFilterProxyRegistrationBean,
* 从而在初始化阶段被注册到Servlet容器中。
*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
//判断当前IOC中是否有SecurityConfigurer,如果没有则使用WebSecurityConfigurerAdapter作为默认配置
//webSecurityConfigurers由上面的setFilterChainProxySecurityConfigurer方法执行后得出
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) { //如果没有找到SecurityConfigurer类型的Bean则执行默认配置
//使用WebSecurityConfigurerAdapter作为配置
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
//添加到WebSecurity中
webSecurity.apply(adapter);
}
//构建过滤器链【会执行本类的performBuild方法完成Filter的创建】
return webSecurity.build();
}
}
接着进一步探究WebSecurity的build方法的执行细节。
在执行WebSecurity实例的build时,会调用父类AbstractConfiguredSecurityBuilder的doBuild()方法,该方法是个模板方法,定义如下:
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
extends AbstractSecurityBuilder<O> {
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
//该方法默认什么都没做
beforeInit();
//以WebSecurity自己为参数调用SecurityConfigurer的init方法
init();
buildState = BuildState.CONFIGURING;
//该方法默认什么都没做
beforeConfigure();
//以WebSecurity自己为参数调用SecurityConfigurer的configure方法
configure();
buildState = BuildState.BUILDING;
//子类中执行Filter的构建操作
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
//供子类实现(WebSecurity)
protected abstract O performBuild() throws Exception;
}
从上到下,我们探究下init()与configure()方法都做了啥
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
extends AbstractSecurityBuilder<O> {
//以WebSecurity自己为参数调用SecurityConfigurer的init方法
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
//具体实现看下面
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
//以WebSecurity自己为参数调用SecurityConfigurer的configure方法
@SuppressWarnings("unchecked")
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
//具体实现看下面
configurer.configure((B) this);
}
}
}
我们以默认的WebSecurityConfigurerAdapter类分析这两个方法的内部实现,毕竟我们基本都是对该类进行扩展来对Spring Security进行定制配置。
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements
WebSecurityConfigurer<WebSecurity> {
public void init(final WebSecurity web) throws Exception {
//创建HttpSecurity的实例(该对象后面会详细探讨)
final HttpSecurity http = getHttp();
//调用WebSecurity的方法将http传递给它保存,
//后面WebSecurity会使用http的build()方法来构建Filter,
//所有真正构建Filter的是这个HttpSecurity 。
//同时,会通过Lambda表达式创建一个Runnable类型的实例
//传递给WebSecurity,待创建好Filter实例后,最后回调该方法
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
//供WebSecurity回调的方法
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
//这里只是简单的给WebSecurity的filterSecurityInterceptor属性赋值
//在WebSecurity的getPrivilegeEvaluator方法中会用到
web.securityInterceptor(securityInterceptor);
});
}
//该方法默认什么都没做
public void configure(WebSecurity web) throws Exception {
}
}
最后我们看下与上面调用有关的WebSecurity中的方法
public final class WebSecurity extends
AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
SecurityBuilder<Filter>, ApplicationContextAware {
private final List<SecurityBuilder<? extends SecurityFilterChain>> securityFilterChainBuilders = new ArrayList<>();
//该方法被WebSecurityConfigurerAdapter的init方法调用【添加进HttpSecurity】
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
//该方法在WebSecurityConfigurerAdapter的init方法调用
public WebSecurity postBuildAction(Runnable postBuildAction) {
this.postBuildAction = postBuildAction;
return this;
}
//该方法被WebSecurityConfigurerAdapter的init方法调用
public WebSecurity securityInterceptor(FilterSecurityInterceptor securityInterceptor) {
this.filterSecurityInterceptor = securityInterceptor;
return this;
}
//完成最后的构建操作
@Override
protected Filter performBuild() throws Exception {
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
//分别执行(HttpSecurity对象)build方法得到SecurityFilterChain
securityFilterChains.add(securityFilterChainBuilder.build());
}
//创建FilterChainProxy ,建立SecurityFilterChain与Servlet容器的桥梁
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
//执行回调
postBuildAction.run();
return result;
}
}
执行流程小结
- WebSecurityConfiguration收集所有的SecurityConfigurer(WebSecurityConfigurerAdapter)并将其传递给WebSecurity;
- WebSecurityConfiguration中执行WebSecurity的build()方法创建springSecurityFilterChain;
- WebSecurity的build()方法中执行各个SecurityConfigurer的init和configure方法完成装配工作,并将装配结果SecurityBuilder<SecurityFilterChain>类型实例添加到WebSecurity的变量securityFilterChainBuilders中;
- WebSecurity的build()方法中继续执行securityFilterChainBuilders中的SecurityBuilder类型对象的build()方法完成SecurityFilterChain实例的创建;
- WebSecurity的build()方法中继续用所有得到的SecurityFilterChain来创建FilterChainProxy实例并返回;
这里面的SecurityConfigurer类型的对象(默认是WebSecurityConfigurerAdapter)是构建SecurityFilterChain的关键,里面的init和configure方法更是完成装配的主要过程,在后面将会对WebSecurityConfigurerAdapter进行深入的分析。