上篇文章通过对WebSecurityConfiguration
这个配置类的源码阅读,已经了解到,在启动的时候主要创建了两个对象,WebSecurity
和名字为springSecurityFilterChain
的Filter
。这篇文章主要是通过源码阅读,查看一下Filter的创建过程,以及后面的工作原理。
1. Filter的创建
1.1再看Filter的创建
/**
* 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 {
//T1 查看是否有WebSecurityConfigurer的相关配置
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
//T2 如果没有,说明我们没有注入继承WebSecurityConfigurerAdapter 的对象
if (!hasConfigurers) {
//T3 创建默认的配置信息WebSecurityConfigurerAdapter ,保证Spring Security的最基础的功能,如果我们要有自定义的相关,一定要重写配置
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
//T4 默认配置信息载入webSecurity
webSecurity.apply(adapter);
}
// T5这里build一个Filter
return webSecurity.build();
}
- T1,T2,T3,T4处的代码请查看代码的注释,这里重点讲解T5处的代码
-
webSecurity
对象在此时已经加载完所有的配置 -
webSecurity
对象为我们创建一个Filter通过的是build()方法
1.2 WebSecurity
的build()
方法
WebSecurity
继承了AbstractConfiguredSecurityBuilder
类,实现了SecurityBuilder
接口.事实上AbstractConfiguredSecurityBuilder
类也是实现了SecurityBuilder
接口。子类和父类实现同一个接口。事实上是为了子类在反射调用方法getInterfaces()
中可以获取到接口,根据这里的情况就是WebSecurity
反射调用getInterfaces()
可以获取到SecurityBuilder
接口(个人理解,也许编写者是另有深意)。-
WebSecurity
的继承关系,了解继承关系,对于后面的代码的理解大有好处
SecurityBuilder
定义了构建的接口标准AbstractSecurityBuilder
实现build方法,用AtomicBoolean的变量building保证多线程情况下,操作的原子性。此处采用的是模板模式。定义了doBuild()抽象方法AbstractConfiguredSecurityBuilder
继承AbstractSecurityBuilder
实现doBuild()方法,也采用模板模式,定义了实现的具体的步骤,如UNBUILT
,INITIALIZING
,CONFIGURING
,BUILDING
,以及BUILT
1.2.1 SecurityBuilder
接口定义
public interface SecurityBuilder<O> {
/**
*
* Builds the object and returns it or null.
* @return the Object to be built or null if the implementation allows it.
* @throws Exception
*
*/
O build() throws Exception;
}
- 该接口的作用是定义一个构建的对象标准
- 只定义了
build()
方法,返回值是一个泛型 - 我们看一下
WebSecurity
的定义
public final class WebSecurity extends
AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
SecurityBuilder<Filter>, ApplicationContextAware {
...
...
}
- 从上面的代码可以看出
WebSecurity
指定泛型的类型为Filter
,结合上面接口build()
方法我们可以知道,WebSecurity
的build()
方法返回的是一个Filter
,Spring Securiy 通过这个来创建一个过滤器
1.2.2 WebSecurity
的build()
过程
- 从上面
WebSecurity
的类图来看,AbstractSecurityBuilder
保证了线程的安全,AbstractConfiguredSecurityBuilder
保证了构建过程以及构建状态。WebSecurity
通过performBuild()来实现自身的构建 -
AbstractConfiguredSecurityBuilder
的构建过程,我们看一下doBuild()方法的定义
@Override
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit(); //默认什么都没做,WebSecurity也没有重写
init(); //T1 默认此处调用WebSecurityConfigurerAdapter的init(final WebSecurity web)方法
buildState = BuildState.CONFIGURING;
beforeConfigure(); //默认什么都不做,WebSecurity没有重写
configure();//调用WebSecurityConfigurerAdapter的configure(WebSecurity web),但是什么都没做
buildState = BuildState.BUILDING;
O result = performBuild(); //T2这里调用WebSecurity的performBuild()方法
buildState = BuildState.BUILT;
return result; //从WebSecurity的实现,这里返回了一个Filter,完成构建过程
}
}
- T1处调用WebSecurityConfigurerAdapter的init(final WebSecurity web)方法,看一下源代码的定义
/**
* @param web
* @throws Exception
*/
public void init(final WebSecurity web) throws Exception {
//构建HttpSecurity对象
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
这里构建了HttpSecurity对象,以及有一个共享对象FilterSecurityInterceptor ,我们还是要将完整的流程讲完,在下一篇文章对HttpSecurity对象做专门的解读,因为这个HttpSecurity对象扮演者非常重要的角色
- T2 , 根据WebSecurity的属性构建Filter的performBuild()方法
@Override
protected Filter performBuild() throws Exception {
Assert.state(
//T1 securityFilterChainBuilders哪里来的?
!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");
//T2 ignoredRequests.size()到底是什么?
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
//这个securityFilterChains 的集合里面存放的就是我们所有的过滤器链,根据长度的定义,我们也可以知道分为两种一个是通过ignoredRequests来的过滤器链,一个是通过securityFilterChainBuilders这个过滤器链构建链来的。
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
//如果是ignoredRequest类型的,那么久添加默认过滤器链(DefaultSecurityFilterChain)
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
//如果是securityFilterChainBuilder类型的,那么通过securityFilterChainBuilder的build()方法来构建过滤器链
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
//将过滤器链交给一个过滤器链代理对象,而这个代理对象就是返回回去的过滤器,后面的代码先不做交代。到这里为止,过滤器的过程已经结束
//T3 什么是FilterChainProxy?
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
if (httpFirewall != null) {
filterChainProxy.setFirewall(httpFirewall);
}
filterChainProxy.afterPropertiesSet();
Filter result = filterChainProxy;
if (debugEnabled) {
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);
}
postBuildAction.run();
return result;
}
从上面源码和标注的注释(也许理解不透彻)来看,其实我们只要回答清楚上面的T1,T2,T3这三个问题,就基本弄清楚了。
1.2.3 WebSecurity
的securityFilterChainBuilders
属性哪里来的
- 我们在上面说到
AbstractConfiguredSecurityBuilder
的doBuild()
里面的init()方法实际上调用的是WebSecurityConfigurerAdapter的init(final WebSecurity web)方法,前面没有详细解释,这里再次引入源码
/**
* @param web
* @throws Exception
*/
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
//T1
web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
public void run() {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
}
});
}
- T1处调用了
WebSecurity
的addSecurityFilterChainBuilder()
方法,我们看一下这个方法的源代码
public WebSecurity addSecurityFilterChainBuilder(
SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder) {
//这个就是securityFilterChainBuilders变量
this.securityFilterChainBuilders.add(securityFilterChainBuilder);
return this;
}
- 从上面两处代码中我们似乎已经知道,在构建Filter过程的初始化的时候,我们对securityFilterChainBuilders这个变量进行了赋值,默认情况下securityFilterChainBuilders里面只有一个对象,那就是
HttpSecurity
1.2.4 ignoredRequests到底是什么
- 其实这个非常简单ignoredRequests只是
WebSecurity
的一个属性 - ignoredRequests的list中的值从哪里来的呢,其实我们可以看到里面有一个ignore()方法,通过这个来进行设置的
- 怎么设置呢,那我们得看看WebSecurityConfigurerAdapter这个类了,里面有一个configure方法供我们重写
public void configure(WebSecurity web) throws Exception {
}
- 具体的例子如下
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring()
.mvcMatchers("/favicon.ico", "/webjars/**", "/css/**");
}
- 然后值得一提的是这里有多少个
mvcMatchers
就会创建多少个ignoredRequests
的对象,也就会有多少个过滤器链,至于源码,可以自行阅读,也是在WebSecurity
里面定义的内部类IgnoredRequestConfigurer
这个类里面
1.2.5 FilterChainProxy
到底是什么
- 上面的描述中我们知道,
FilterChainProxy
是真正返回的Filter,上面代码中FilterChainProxy
的对象创建的源码为:
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
- 然后这个FilterChainProxy又是比较复杂的玩意儿,我们还是在接下来文章继续吧。
1.3 过滤器实现的流程
- 虽然到目前为止,整个还是没有交代清楚,但是我们还是需要画一个小图来整理一下前面的流程吧。为接下来
HttpSecurity
和FilterChainProxy
类解读做点准备
我们暂时的放过一下FilterChainProxy
,下一篇我们继续HttpSecurity