在前面的三篇文章中,已经大概交代了一下三个地方
spring security
启动WebSecurityConfiguration
主要做了两件事情:
1.根据WebSecurityConfigurerAdapter
中配置的信息创建WebSecurity
这个类
2.springSecurityFilterChain()
创建了一个名叫springSecurityFilterChain
的过滤器,然后值得一提的是在调用WebSecurity
的build()
创建过滤器的时候,调用到了WebSecurity
的init()
方法创建了一个HttpSecurity
的对象,这里会根据配置为我们创建过滤器,最后添加到DefaultSecurityFilterChain
过滤器链里面来
Spring Security(一) 启动原理spring security
后面讲到过滤器创建的过程,其实主要是过滤器链,比如ignoreRequests是怎样创建过滤器的
Spring Security(二) 过滤器原理后面我们讲到一个非常重要的类
HttpSecurity
讲到,其中重点通过formLogin()
这个方法通过源码看了一下怎样通过对HttpSecurity
的配置最后转换到Filter
。以及怎样直接通过addFilterXXX
来添加一个过滤器
Spring Security(三) HttpSecurity然后我们到此为止,还是没有弄懂过滤器最终的结构,以及在零散的源代码阅读背后,还差一个关于过滤器的总体的把握。
1.为什么要说这个类
在前面的文章中我们已经说到所有的过滤器链都添加到了securityFilterChains
这个列表中,后面出现了下面一行代码
FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
我们知道FilterChainProxy
的bean的名字叫做springSecurityFilterChain
里面包含了我们的过滤器链
所以我们必须要清楚他的工作原理
2.类的简单说明
2.1变量
2.1.1 filterChains
变量定义
private List filterChains
- 里面存储了过滤器链的信息
2.2构造函数
public FilterChainProxy(List filterChains) {
this.filterChains = filterChains;
}
在WebSecurity
的performBuild()
方法中我们对于spring security的配置最后生成的过滤器链设置到filterChains
这个变量中
3.虚拟过滤器链VirtualFilterChain
private static class VirtualFilterChain implements FilterChain {
//原始过滤器链,代表了spring 的application context中所有的过滤器连
//其实可以参考DelegatingFilterProxy
private final FilterChain originalChain;
//spring security的过滤器链
private final List additionalFilters;
//因为在FilterChainProxy中request和response被封装到HttpFirewall中,所以我们从这里获取请求信息
private final FirewalledRequest firewalledRequest;
//spring security的过滤器的长度
private final int size;
//当前执行到的位置
private int currentPosition = 0;
private VirtualFilterChain(FirewalledRequest firewalledRequest,
FilterChain chain, List additionalFilters) {
this.originalChain = chain;
this.additionalFilters = additionalFilters;
this.size = additionalFilters.size();
this.firewalledRequest = firewalledRequest;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
//表示spring security的过滤器全部执行完成,那么可以执行spring的application context 中的其他的过滤器链了
if (currentPosition == size) {
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " reached end of additional filter chain; proceeding with original chain");
}
// Deactivate path stripping as we exit the security filter chain
this.firewalledRequest.reset();
originalChain.doFilter(request, response);
}
else {
//获取当前过滤器执行到的为止
currentPosition++;
//当前需要执行的过滤器
Filter nextFilter = additionalFilters.get(currentPosition - 1);
if (logger.isDebugEnabled()) {
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+ " at position " + currentPosition + " of " + size
+ " in additional filter chain; firing Filter: '"
+ nextFilter.getClass().getSimpleName() + "'");
}
//执行当前的过滤器
nextFilter.doFilter(request, response, this);
}
}
}
4 FilterChainProxy
的doFilter
方法
我们知道FilterChainProxy
已经被注册到application context中,那么就会被DelegatingFilterProxy
执行到自己的doFilter()
方法,然而先没必要想这么多,就把FilterChainProxy
当成我们在web.xml中定义的一个Filter就行,当有请求进来就会去执行doFilter
方法
@Override
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);
doFilterInternal(request, response, chain);
}
finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
else {
doFilterInternal(request, response, chain);
}
}
private void doFilterInternal(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FirewalledRequest fwRequest = firewall
.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse fwResponse = firewall
.getFirewalledResponse((HttpServletResponse) response);
List filters = getFilters(fwRequest);
if (filters == null || filters.size() == 0) {
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);
return;
}
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
}
- 上面这么多行的代码其实我们大概捋顺一下就知道,主要的无非就是当有请求,判断当前过滤器列表里面是否有过滤器,如果没有执行spring application context中的其他的过滤器链,如果有执行一下两行代码
VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
- 首先新建了一个虚拟过滤器链,请参考上面的代码
- 其次执行了doFilter()方法
- 根据上面对于
VirtualFilterChain
的源代码注释,我们是可以看到过滤器链是怎样被执行完的。
5.总结
这个类还是比较简单和清晰明了的。没有晦涩的继承关系。到此为止,我们已经了解到了spring security 的一个请求过来为什么会去穿透我们的过滤器,可以说对于spring security的启动,spring security filter chain的组建,我们基本已经了解完成,最后,在默认情况下进行调试,我们看一下我们的默认的过滤器有哪些,也顺便结束这篇文章吧.