详解spring security filter的工作原理
这篇文章介绍filter的工作原理。配置方式为xml。
Filter如何进入执行逻辑的
初始配置:
springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain /*
DelegatingFilterProxy这个类继承了GenericFilterBean,GenericFilterBean实现了Filter接口。
这个配置是一切的开始,配置完这个之后,在启动项目的时候会执行Filterd的初始化方法:
@Override
publicfinalvoidinit(FilterConfigfilterConfig)throwsServletException{
Assert.notNull(filterConfig,"FilterConfigmustnotbenull");
if(logger.isDebugEnabled()){
logger.debug("Initializingfilter'"+filterConfig.getFilterName()+"'");
}
this.filterConfig=filterConfig;
//Setbeanpropertiesfrominitparameters.
PropertyValuespvs=newFilterConfigPropertyValues(filterConfig,this.requiredProperties);
if(!pvs.isEmpty()){
try{
BeanWrapperbw=PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoaderresourceLoader=newServletContextResourceLoader(filterConfig.getServletContext());
Environmentenv=this.environment;
if(env==null){
env=newStandardServletEnvironment();
}
bw.registerCustomEditor(Resource.class,newResourceEditor(resourceLoader,env));
initBeanWrapper(bw);
bw.setPropertyValues(pvs,true);
}
catch(BeansExceptionex){
Stringmsg="Failedtosetbeanpropertiesonfilter'"+
filterConfig.getFilterName()+"':"+ex.getMessage();
logger.error(msg,ex);
thrownewNestedServletException(msg,ex);
}
}
//Letsubclassesdowhateverinitializationtheylike.
initFilterBean();//这个方法
if(logger.isDebugEnabled()){
logger.debug("Filter'"+filterConfig.getFilterName()+"'configuredsuccessfully");
}
}
在初始化方法中,会执行初始化Filter的方法initFilterBean。这个方法的实现在DelegatingFilterProxy中:
protectedvoidinitFilterBean()throwsServletException{
synchronized(this.delegateMonitor){
if(this.delegate==null){
//Ifnotargetbeannamespecified,usefiltername.
if(this.targetBeanName==null){
this.targetBeanName=getFilterName();
}
//FetchSpringrootapplicationcontextandinitializethedelegateearly,
//ifpossible.Iftherootapplicationcontextwillbestartedafterthis
//filterproxy,we'llhavetoresorttolazyinitialization.
WebApplicationContextwac=findWebApplicationContext();
if(wac!=null){
this.delegate=initDelegate(wac);//这个方法
}
}
}
}
在这个初始化方法中又调用initDelegate方法进行初始化:
protectedFilterinitDelegate(WebApplicationContextwac)throwsServletException{
StringtargetBeanName=getTargetBeanName();
Assert.state(targetBeanName!=null,"Notargetbeannameset");
Filterdelegate=wac.getBean(targetBeanName,Filter.class);
if(isTargetFilterLifecycle()){
delegate.init(getFilterConfig());
}
returndelegate;
}
在这个方法中,先获取targetBeanName,这个名字是构造方法中赋值的:
publicDelegatingFilterProxy(StringtargetBeanName,@NullableWebApplicationContextwac){
Assert.hasText(targetBeanName,"TargetFilterbeannamemustnotbenullorempty");
this.setTargetBeanName(targetBeanName);
this.webApplicationContext=wac;
if(wac!=null){
this.setEnvironment(wac.getEnvironment());
}
}
这个名字就是web.xml中配置的名字springSecurityFilterChain:
springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain是固定不能改的,如果改了启动时就会报错,这是spring启动时内置的一个bean,这个bean实际是FilterChainProxy。
这样一个Filter就初始化话好了,过滤器chain也初始化好了。
当一个请求进来的时候,会进入FilterChainProxy执行doFilter方法:
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
booleanclearContext=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);
}
}
先获取所有的Filter,然后执行doFilterInternal方法:
privatevoiddoFilterInternal(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
FirewalledRequestfwRequest=firewall
.getFirewalledRequest((HttpServletRequest)request);
HttpServletResponsefwResponse=firewall
.getFirewalledResponse((HttpServletResponse)response);
Listfilters=getFilters(fwRequest);
if(filters==null||filters.size()==0){
if(logger.isDebugEnabled()){
logger.debug(UrlUtils.buildRequestUrl(fwRequest)
+(filters==null?"hasnomatchingfilters"
:"hasanemptyfilterlist"));
}
fwRequest.reset();
chain.doFilter(fwRequest,fwResponse);
return;
}
//最终执行下面的这些代码
VirtualFilterChainvfc=newVirtualFilterChain(fwRequest,chain,filters);
vfc.doFilter(fwRequest,fwResponse);
}
VirtualFilterChain是一个匿名内部类:
privatestaticclassVirtualFilterChainimplementsFilterChain{
privatefinalFilterChainoriginalChain;
privatefinalListadditionalFilters;
privatefinalFirewalledRequestfirewalledRequest;
privatefinalintsize;
privateintcurrentPosition=0;
privateVirtualFilterChain(FirewalledRequestfirewalledRequest,
FilterChainchain,ListadditionalFilters){
this.originalChain=chain;
this.additionalFilters=additionalFilters;
this.size=additionalFilters.size();
this.firewalledRequest=firewalledRequest;
}
@Override
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse)
throwsIOException,ServletException{
if(currentPosition==size){
if(logger.isDebugEnabled()){
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+"reachedendofadditionalfilterchain;proceedingwithoriginalchain");
}
//Deactivatepathstrippingasweexitthesecurityfilterchain
this.firewalledRequest.reset();
originalChain.doFilter(request,response);
}
else{
currentPosition++;
FilternextFilter=additionalFilters.get(currentPosition-1);
if(logger.isDebugEnabled()){
logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
+"atposition"+currentPosition+"of"+size
+"inadditionalfilterchain;firingFilter:'"
+nextFilter.getClass().getSimpleName()+"'");
}
nextFilter.doFilter(request,response,this);
}
}
}
filter集合执行的逻辑在VirtualFilterChain的doFilter方法中。
filter是如何执行的
上面说了怎么才能进入filter的执行逻辑,下面说一下filter到底怎么执行,为什么一个
在VirtualFilterChain的doFilter方法可以执行所有的filter。
下面写一个例子,模拟filter的执行逻辑。
定义FilterChain接口、Filter接口:
publicinterfaceFilter{
voiddoFilter(Stringusername,intage,FilterChainfilterChain);
}
publicinterfaceFilterChain{
voiddoFilter(Stringusername,intage);
}
定义两个Filter实现:
publicclassNameFilterimplementsFilter{
@Override
publicvoiddoFilter(Stringusername,intage,FilterChainfilterChain){
username=username+1;
System.out.println("username:"+username+"age:"+age);
System.out.println("正在执行:NameFilter");
filterChain.doFilter(username,age);
}
}
publicclassAgeFilterimplementsFilter{
@Override
publicvoiddoFilter(Stringusername,intage,FilterChainfilterChain){
age+=10;
System.out.println("username:"+username+"age:"+age);
System.out.println("正在执行:AgeFilter");
filterChain.doFilter(username,age);
}
}
定义一个FilterChain实现:
publicclassFilterChainProxyimplementsFilterChain{
privateintposition=0;
privateintsize=0;
privateListfilterList=newArrayList<>();
publicvoidaddFilter(Filterfilter){
filterList.add(filter);
size++;
}
@Override
publicvoiddoFilter(Stringusername,intage){
if(size==position){
System.out.println("过滤器链执行结束");
}else{
Filterfilter=filterList.get(position);
position++;
filter.doFilter(username,age,this);
}
}
}
测试Filter实现:
publicclassFilterTest{
publicstaticvoidmain(String[]args){
FilterChainProxyproxy=newFilterChainProxy();
proxy.addFilter(newNameFilter());
proxy.addFilter(newAgeFilter());
proxy.doFilter("张三",0);
}
}
=======
username:张三1age:0
正在执行:NameFilter
username:张三1age:10
正在执行:AgeFilter
过滤器链执行结束
在这个执行逻辑中,最重要的是【this】,this就是初始化的好的FilterChain实例,在这个测试实例中,this就是FilterChainProxy。
执行FilterChainProxy的doFilter方法的时候,传入了初始参数username和age,进入这个方法后,根据position取出相应的Filter,初次进入position是0,执行Filter的doFilter方法,注意,此时Filter的doFilter方法额外传入了一个this参数,这个参数就是初始化的好的FilterChain实例,在Filter中的doFilter的方法中最后又会执行FilterChain的doFilter方法,相当于第二次调用FilterChain实例的doFilter方法,此时posotion是1,然后再执行Filter的doFilter方法,直到所有的Filter执行完,整个执行过程结束。
VirtualFilterChain的doFilter方法的执行逻辑和这个测试实例中的执行逻辑基本一致。
这样就完成了整个过滤器链的执行。
总结
以前用Filter的时候就非常疑惑过滤器怎么执行的,直到今天才算解决了这个疑惑。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。