
一、spring security 的三大配置
- 我们配置 spring security 主要是通过继承
WebSecurityConfigurerAdapter类来实现,其中主要有 3 个方法configure(AuthenticationManagerBuilder auth),此方法用于设置用户的权限认证configure(HttpSecurity http),此方法用于配置 http 协议,比如设置session管理,设置是否启用 CSRF 等configure(WebSecurity web),此方法用于配置访问资源的限制,经常用来过滤静态资源的校验
二、启动流程
@EnableWebSecurity- 使用
@Import实例化了类WebSecurityConfiguration,该类主要做了以下两个工作setFilterChainProxySecurityConfigurer方法将我们自定义的配置信息存放在webSecurity对象中.
webSecurity 其实就是一个 filter,但是需要通过调用 build 才能返回 filterspringSecurityFilterChain方法为我们创建一个默认的 filter.
当然如果我们自定义类继承了 WebSecurityConfigurerAdapter 就不会创建默认的
- 使用
三、过滤器初始化
1、在阅读源码之前
在介绍过滤器的初始化之前我们先记住下面这个继承关系,便于后面的理解

- SecurityBuilder 接口只有一个
build()方法 - AbstractSecurityBuilder 使用 CAS 保证
build()方法的原子性,然后将真正的build()操作交给doBuild() - AbstractConfiguredSecurityBuilder 实现
doBuild()方法,定义了具体的步骤以及 build 的各个状态 - WebSecurity 实现
performBuild()来完成最终的真正的 build
这几个类就是设计模式中很典型的
模板模式
2、初始化过程
在之前的启动流程中我们说到 WebSecurityConfiguration 类的 springSecurityFilterChain 方法会为我们创建一个 filter,看一下代码:
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}
在这个方法的最后一行,我们看到了调用了 build() 方法,这个方法就是过滤器初始化的入口了,build() 流程如下:
- 执行父类
AbstractSecurityBuilder的build() - 执行父类
AbstractConfiguredSecurityBuilder的doBuild() - 执行当前类也就是
WebSecurity类的performBuild()
现在我们来仔细看一看 WebSecurity 类的 performBuild() 方法具体做了些什么,源码:
protected Filter performBuild() throws Exception {
// question 1:securityFilterChainBuilders是什么时候初始化的?
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");
// question 2:ignoredRequests什么时候初始化的?
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
// 将ignoredRequests和securityFilterChainBuilders中的元素封装一下,然后存放进securityFilterChains中
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
securityFilterChains.add(securityFilterChainBuilder.build());
}
// 代理securityFilterChains
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;
}
- question 1
AbstractConfiguredSecurityBuilder#doBuild()->AbstractConfiguredSecurityBuilder#init()->WebSecurityConfigurerAdapter#init(..)->WebSecurity#addSecurityFilterChainBuilder(..)- 最终在 addSecurityFilterChainBuilder 方法中初始化了
securityFilterChainBuilders,你要是问我doBuild方法又是哪来的,很简单之前就说过了,是 WebSecurity 的 build()调用的
- question 2
IgnoredRequestConfigurer#mvcMatchers(..)->WebSecurity#mvcMatchers(..)- 那系统是在何时使用过
IgnoredRequestConfigurer#mvcMatchers(..)方法的呢?很简单
我们在使用 spring security 的时候都会继承WebSecurityConfigurerAdapter类重新一些配置方法,其中有一个配置方法一般会如下使用:@Override public void configure(WebSecurity web) throws Exception { web.ignoring().mvcMatchers("/images/**"); web.ignoring().mvcMatchers("/js/**"); web.ignoring().mvcMatchers("/css/**"); web.ignoring().mvcMatchers("/lib/**"); // web.ignoring()方法只是返回内部类IgnoredRequestConfigurer的实例 // 我们就是在这儿使用了IgnoredRequestConfigurer#mvcMatchers(..) }
- 上面的这两个问题解决了,接着就是各种代理了,然后返回被代理的过滤器链
总结一下本方法的作用:就是找到我们配置或者默认配置的一些过滤器,然后代理封装一下,最后组成一个过滤器链再返回
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于