7、Spring Security过滤器及加载过程

Spring Security介绍及过滤器

1 、Spring Security常用过滤器介绍

过滤器是一种典型的AOP思想,关于什么是过滤器,就不赘述了,谁还不知道凡是web工程都能用过滤器?

接下来咱们就一起看看Spring Security中这些过滤器都是干啥用的,源码我就不贴出来了,有名字,大家可以自

己在看。我也会在后续的学习过程中穿插详细解释。** 、

1.org.springframework.security.web.context.SecurityContextPersistenceFilter 
	首当其冲的一个过滤器,作用之重要,自不必多言。 
	SecurityContextPersistenceFilter主要是使用SecurityContextRepository在session中保存或更新一个 SecurityContext,并将SecurityContext给以后的过滤器使用,来为后续fifilter建立所需的上下文。 
SecurityContext中存储了当前用户的认证以及权限信息。 

2.org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter 
	此过滤器用于集成SecurityContextSpring异步执行机制中的WebAsyncManager 
	
3. org.springframework.security.web.header.HeaderWriterFilter 
	向请求的Header中添加相应的信息,可在http标签内部使用security:headers来控制 

4. org.springframework.security.web.csrf.CsrfFilter 
	csrf又称跨域请求伪造,SpringSecurity会对所有post请求验证是否包含系统生成的csrf的token信息,如果不包含,则报错。起到防止csrf攻击的效果。 

5. org.springframework.security.web.authentication.logout.LogoutFilter 
	匹配URL为/logout的请求,实现用户退出,清除认证信息。 

6. org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter 
	认证操作全靠这个过滤器,默认匹配URL为/login且必须为POST请求。 

7. org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter 
	如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面。 

8. org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter 
	由此过滤器可以生产一个默认的退出登录页面 

9. org.springframework.security.web.authentication.www.BasicAuthenticationFilter 
	此过滤器会自动解析HTTP请求中头部名字为Authentication,且以Basic开头的头信息。 

10. org.springframework.security.web.savedrequest.RequestCacheAwareFilter 
	通过HttpSessionRequestCache内部维护了一个RequestCache,用于缓存HttpServletRequest 

11. org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter 
	针对ServletRequest进行了一次包装,使得request具有更加丰富的API 

12. org.springframework.security.web.authentication.AnonymousAuthenticationFilterSecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到SecurityContextHolder中。		spring security为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。 

13. org.springframework.security.web.session.SessionManagementFilter 
	SecurityContextRepository限制同一用户开启多个会话的数量 

14. org.springframework.security.web.access.ExceptionTranslationFilter 
	异常转换过滤器位于整个springSecurityFilterChain的后方,用来转换整个链路中出现的异常 
	
15. org.springframework.security.web.access.intercept.FilterSecurityInterceptor 
	获取所配置资源访问的授权信息,根据SecurityContextHolder中存储的用户信息来决定其是否有权限。 

好了!这一堆排山倒海的过滤器介绍完了。

那么,是不是spring security一共就这么多过滤器呢?答案是否定的!随着spring-security.xml配置的添加,还

会出现新的过滤器。

那么,是不是spring security每次都会加载这些过滤器呢?答案也是否定的!随着spring-security.xml配置的修

改,有些过滤器可能会被去掉。

2、Spring Security过滤器链加载原理

通过前面十五个过滤器功能的介绍,对于SpringSecurity简单入门中的疑惑是不是在心中已经有了答案了呀?

它们都是怎么被加载出来的?

2.1 DelegatingFilterProxy

首先是名称为springSecurityFilterChain的过滤器DelegatingFilterProxy,接下我直接对

DelegatingFilterProxy源码里重要代码进行说明,其中删减掉了一些不重要的代码,大家注意我写的注释就行了!

public class DelegatingFilterProxy extends GenericFilterBean { 

@Nullable 

private String contextAttribute; 

@Nullable 

private WebApplicationContext webApplicationContext; 

@Nullable 

private String targetBeanName; 

private boolean targetFilterLifecycle; 

@Nullable 

private volatile Filter delegate;//注:这个过滤器才是真正加载的过滤器 

private final Object delegateMonitor; 

//注:doFilter才是过滤器的入口,直接从这看! 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain 

filterChain) throws ServletException, IOException { 

Filter delegateToUse = this.delegate; 

if (delegateToUse == null) { 

synchronized(this.delegateMonitor) { 

delegateToUse = this.delegate; 

if (delegateToUse == null) { 

WebApplicationContext wac = this.findWebApplicationContext(); 

if (wac == null) { 

throw new IllegalStateException("No WebApplicationContext found: no 

ContextLoaderListener or DispatcherServlet registered?"); 

}

//第一步:doFilter中最重要的一步,初始化上面私有过滤器属性delegate 

delegateToUse = this.initDelegate(wac); 

}

this.delegate = delegateToUse; 

} 

}

//第三步:执行FilterChainProxy过滤器 

this.invokeDelegate(delegateToUse, request, response, filterChain); 

}

//第二步:直接看最终加载的过滤器到底是谁 

protected Filter initDelegate(WebApplicationContext wac) throws ServletException { 

//debug得知targetBeanName为:springSecurityFilterChain 

String targetBeanName = this.getTargetBeanName(); 

Assert.state(targetBeanName != null, "No target bean name set"); 

//debug得知delegate对象为:FilterChainProxy 

Filter delegate = (Filter)wac.getBean(targetBeanName, Filter.class); 

if (this.isTargetFilterLifecycle()) { 

delegate.init(this.getFilterConfig()); 

}

return delegate; 
}       

第二步debug结果如下:

由此可知,DelegatingFilterProxy通过springSecurityFilterChain这个名称,得到了一个FilterChainProxy过滤器,

最终在第三步执行了这个过滤器。

2.2 FilterChainProxy

注意代码注释!注意代码注释!注意代码注释!

protected void invokeDelegate(Filter delegate, ServletRequest request, ServletResponse 

response, FilterChain filterChain) throws ServletException, IOException { 

delegate.doFilter(request, response, filterChain); 

} 

}

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"); 

private List<SecurityFilterChain> filterChains; 

private FilterChainProxy.FilterChainValidator filterChainValidator; 

private HttpFirewall firewall; 

//咿!?可以通过一个叫SecurityFilterChain的对象实例化出一个FilterChainProxy对象 

//这FilterChainProxy又是何方神圣?会不会是真正的过滤器链对象呢?先留着这个疑问! 

public FilterChainProxy(SecurityFilterChain chain) { 

this(Arrays.asList(chain)); 

}

//又是SecurityFilterChain这家伙!嫌疑更大了! 

public FilterChainProxy(List<SecurityFilterChain> filterChains) { 

this.filterChainValidator = new FilterChainProxy.NullFilterChainValidator(); 

this.firewall = new StrictHttpFirewall(); 

this.filterChains = filterChains; 

}

//注:直接从doFilter看 

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 { 

//第一步:具体操作调用下面的doFilterInternal方法了 

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 List<Filter> getFilters(HttpServletRequest request) { 

Iterator var2 = this.filterChains.iterator(); 

//第三步:封装过滤器链到SecurityFilterChain中! 

SecurityFilterChain chain; 

do {

if (!var2.hasNext()) { 

return null; 

} 

第二步debug结果如下图所示,惊不惊喜?十五个过滤器都在这里了!

再看第三步,怀疑这么久!原来这些过滤器还真是都被封装进SecurityFilterChain中了。

2.3 SecurityFilterChain

最后看SecurityFilterChain,这是个接口,实现类也只有一个,这才是web.xml中配置的过滤器链对象!

chain = (SecurityFilterChain)var2.next(); 

} while(!chain.matches(request)); 

return chain.getFilters(); 

} 

}

//接口 

public interface SecurityFilterChain { 

boolean matches(HttpServletRequest var1); 

List<Filter> getFilters(); 

}

//实现类 

public final class DefaultSecurityFilterChain implements SecurityFilterChain { 

private static final Log logger = LogFactory.getLog(DefaultSecurityFilterChain.class); 

private final RequestMatcher requestMatcher; 

private final List<Filter> filters; 

public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) { 

总结:通过此章节,我们对SpringSecurity工作原理有了一定的认识。但理论千万条,功能第一条,探寻底层,是为了更好的使用框架。


你可能感兴趣的:(认证授权服务实战(鉴权),spring,java,前端)