活动地址:CSDN21天学习挑战赛
在 SpringSecurity - 启动流程分析(二) 这篇文章中,我们分析了 HttpSecurity 是如何转换为 List,并最终放入 DefaultSecurityFilterChain 的。
// HttpSecurity 的 build() 方法
@Override
protected DefaultSecurityFilterChain performBuild() {
filters.sort(comparator);
return new DefaultSecurityFilterChain(requestMatcher, filters);
}
WebSecurity 的 build() 方法在之后的逻辑中把 DefaultSecurityFilterChain 添加到了 List 中,然后把 List 作为参数 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 BeanspringSecurityFilterChain Bean 是一个类型为 Filter 的 FilterChainProxyFilterChainProxy 中包含了 DefaultSecurityFilterChain 过滤器链DefaultSecurityFilterChain 过滤器链中是由 HttpSecurity 转化而来的 Filters从 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 中的 Filters,而 originalChain 是 Servlet 容器中的过滤器链,也就是 ApplicationFilterChain。

这里的
ApplicationFilterConfig在之后的 Tomcat 学习 专栏再进行分析,这里主要是理解SpringSecurity的过滤逻辑
