shiro过滤原理。

           项目中用了shiro很久了,但对于其执行原理一直没研究过。后来在项目中做防盗链功能时候,因为不能拦截被shiro认证的白名单接口,不得不研究了shiro源码。

 

1、shiro首先是一个过滤器,filter基本功能肯定有。

     我们知道filter最重要的一个接口是   void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)。

    所以我们由这里开始.

   abstract class OncePerRequestFilter extends NameableFilter {
        public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain){
             //略
             doFilterInternal(request, response, filterChain);
        }
    }

   这个抽象类里面有个final的doFilter()函数,因为是final,所以其真正的实现放在doFilterInternal。

2、doFilterInternal函数

   

	abstract class AbstractShiroFilter extends OncePerRequestFilter{

		protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain){
			final Subject subject = createSubject(request, response);
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    updateSessionLastAccessTime(request, response);
                    executeChain(request, response, chain);
                    return null;
                }
            });
		}

   这里我们主要看 executeChain(request, response, chain);

 

3. executeChain函数

protected void executeChain(ServletRequest req,ServletResponse resp,FilterChain origChain) {
              FilterChain chain = getExecutionChain(reqt, res, origChain);
              chain.doFilter(req, res);
        }

只有两个步骤,首先是获取shiro自定义的过滤链对象,然后执行shiro自定义的过滤。这里只讨论getExecutionChain函数

4.getExecutionChain函数

 

protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain){
			//略
			FilterChainResolver resolver =getFilterChainResolver();		
			FilterChain chain = resolver.getChain(request, response, origChain);
			return chain;
		}

这个函数是首先获取一个过滤链解析器,然后通过解析器再去获取过滤链对象 。这里要说下,获取的解析器resolver

其实在项目启动时就被实例好了,作为shiro对象的一个属性。这个属性也是定义在AbstractShiroFilter类中

private FilterChainResolver filterChainResolver;

至于怎么初始化这个对象,这里就不讨论了,有兴趣的可以研究下shiro的实例化过程,它是被工厂生产出来的。

继续回归之前的话题,看看 resolver.getChain(request, response, origChain)函数

5. resolver.getChain(request, response, origChain)函数

public class PathMatchingFilterChainResolver implements FilterChainResolver{
	public FilterChain getChain(request,response,originalChain){
		FilterChainManager filterChainManager = getFilterChainManager();
		String requestURI = getPathWithinApplication(request);
		for (String pathPattern : filterChainManager.getChainNames()) {
			if (pathMatches(pathPattern, requestURI)) {
			     return filterChainManager.proxy(originalChain, pathPattern);
			  }
		}
	}
	public FilterChainManager getFilterChainManager() {
             return filterChainManager;
        }

	private FilterChainManager filterChainManager
}

filterChainManager对象也会在项目启动时进行实例化。这里就不讨论了。

我们看看 filterChainManager.getChainNames() 函数,记得shiro配置时的 filterChainDefinitions吗?

	    <property name="filterChainDefinitions">
	        <value>
	        	/statics/**=anon
			/api/**=anon
	        </value>
	    </property>

 filterChainManager.getChainNames() 获取出来的就是配置的shiro过滤路径。

这样,如果ruquest的url能够匹配 filterChainManager.getChainNames() 中的过滤路径,就返回对应chain。

6.  filterChainManager.proxy(originalChain, pathPattern)函数

    这个其实没什么好说的,就是根据相应的url生成一个filterChain对象。

   重点看看生成的filterChain对象有什么属性,FilterChain是个接口,其最终的实现类是ProxiedFilterChain

   看看ProxiedFilterChain 类的属性和方法

public class ProxiedFilterChain implements FilterChain {
    private FilterChain orig;
    private List<Filter> filters;
    private int index = 0;

    public void doFilter(ServletRequest request, ServletResponse response)  {
        if (this.filters == null || this.filters.size() == this.index) {
            //we've reached the end of the wrapped chain, so invoke the original one:
            if (log.isTraceEnabled()) {
                log.trace("Invoking original filter chain.");
            }
            this.orig.doFilter(request, response);
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Invoking wrapped filter at index [" + this.index + "]");
            }
            this.filters.get(this.index++).doFilter(request, response, this);
        }
    }
}

 

可以看到有个filter列表属性。首先项目启动时,会缓存shiro内置的全部Filter对象。

这样每一个请求来到,shiro都能保证请求能找到对应的Filter对象,然后不同的Filter对象都有自己的doFilter逻辑。

而且可以看到当filters存在多个时,会先循环执行完,然后再交给下一个过滤器。

所以,我们在web.xml配置过滤器时,应该把shiro过滤器放在最前面。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值