活动地址:优快云21天学习挑战赛
承上启下
在 SpringSecurity - 启动流程分析(二) 这篇文章中,我们分析了 HttpSecurity
是如何转换为 List<Filter>
,并最终放入 DefaultSecurityFilterChain
的。
// HttpSecurity 的 build() 方法
@Override
protected DefaultSecurityFilterChain performBuild() {
filters.sort(comparator);
return new DefaultSecurityFilterChain(requestMatcher, filters);
}
WebSecurity
的 build()
方法在之后的逻辑中把 DefaultSecurityFilterChain
添加到了 List<SecurityFilterChain>
中,然后把 List<SecurityFilterChain>
作为参数 new
了一个 FilterChainProxy
类作为方法返回对象
for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
// 这里的 securityFilterChainBuilder 就是 HttpSecurity,build() 方法返回了 DefaultSecurityFilterChain
securityFilterChains.add(securityFilterChainBuilder.build());
}
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
...
Filter result = filterChainProxy;
...
return result;
也就是说 SpringSecurity - 启动流程分析(一) 中的核心配置类 WebSecurityConfiguration
中的核心流程: springSecurityFilterChain()
方法返回的是一个 FilterChainProxy
(又回到最初的起点)。
@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();
}
到此为止,我们知道了:
@EnableWebSecurity
注解为IoC 容器
中添加了WebSecurityConfiguration
配置类WebSecurityConfiguration
配置类为容器中添加了springSecurityFilterChain
Bean
springSecurityFilterChain
Bean
是一个类型为Filter
的FilterChainProxy
FilterChainProxy
中包含了DefaultSecurityFilterChain
过滤器链DefaultSecurityFilterChain
过滤器链中是由HttpSecurity
转化而来的Filter
s
从 SpringBoot - 配置 Filter 的几种方式 文章中我们知道,在容器中添加一个 Filter
类型的 Bean
,就会拦截所有请求,但是从上面代码中我们看到返回的是一个 FilterChainProxy
:
从源码中可以看到,继承了
GenericFilterBean
,关于GenericFilterBean
可以查看 SpringMVC - 对于如何配置 Filter 的深度剖析 这篇文章
public class FilterChainProxy extends GenericFilterBean {
private static final Log logger = LogFactory.getLog(FilterChainProxy.class);
private static final String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");
// 这里就是传进来的 DefaultSecurityFilterChain,当然还包含了其他的 SecurityFilterChain
private List<SecurityFilterChain> filterChains;
...
public FilterChainProxy(List<SecurityFilterChain> filterChains) {
this.filterChainValidator = new FilterChainProxy.NullFilterChainValidator();
this.firewall = new StrictHttpFirewall();
// 过滤器链,可以打印一下看看里面都有啥
this.filterChains = filterChains;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
this.doFilterInternal(request, response, chain);
} finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
} else {
this.doFilterInternal(request, response, chain);
}
}
private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FirewalledRequest fwRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);
HttpServletResponse fwResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);
List<Filter> filters = this.getFilters((HttpServletRequest)fwRequest);
if (filters != null && filters.size() != 0) {
// 虚拟过滤器链
FilterChainProxy.VirtualFilterChain vfc = new FilterChainProxy.VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
} else {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(fwRequest) + (filters == null ? " has no matching filters" : " has an empty filter list"));
}
fwRequest.reset();
chain.doFilter(fwRequest, fwResponse);
}
}
...
private static class VirtualFilterChain implements FilterChain {
// Servlet 容器中的原始过滤器链
private final FilterChain originalChain;
// SpringSecurity 的过滤器链
private final List<Filter> additionalFilters;
private final FirewalledRequest firewalledRequest;
private final int size;
private int currentPosition;
private VirtualFilterChain(FirewalledRequest firewalledRequest, FilterChain chain, List<Filter> additionalFilters) {
this.currentPosition = 0;
this.originalChain = chain;
this.additionalFilters = additionalFilters;
this.size = additionalFilters.size();
this.firewalledRequest = firewalledRequest;
}
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
// SpringSecurity 中的 Filter 执行完之后,接着执行 Servlet 容器中的 Filter
if (this.currentPosition == this.size) {
if (FilterChainProxy.logger.isDebugEnabled()) {
FilterChainProxy.logger.debug(UrlUtils.buildRequestUrl(this.firewalledRequest) + " reached end of additional filter chain; proceeding with original chain");
}
this.firewalledRequest.reset();
this.originalChain.doFilter(request, response);
} else {
// 执行 SpringSecurity 中的 Filter,知道执行完为止
++this.currentPosition;
Filter nextFilter = (Filter)this.additionalFilters.get(this.currentPosition - 1);
if (FilterChainProxy.logger.isDebugEnabled()) {
FilterChainProxy.logger.debug(UrlUtils.buildRequestUrl(this.firewalledRequest) + " at position " + this.currentPosition + " of " + this.size + " in additional filter chain; firing Filter: '" + nextFilter.getClass().getSimpleName() + "'");
}
nextFilter.doFilter(request, response, this);
}
}
}
}
项目启动时 Debug
看一下 FilterChainProxy
中的 filterChains
会被初始化为什么:
当有请求进来时,Debug
看一下 VirtualFilterChain
构造完成后包含的参数:
可以看到,正如上面所分析的,additionalFilters
中是 SpringSecurity
中的 Filter
s,而 originalChain
是 Servlet
容器中的过滤器链,也就是 ApplicationFilterChain
。
这里的
ApplicationFilterConfig
在之后的 Tomcat 学习 专栏再进行分析,这里主要是理解SpringSecurity
的过滤逻辑