【Shiro学习】ShiroFilter源码分析

通过上篇对FilterChainManager的学习,可以知道,FilterChainManager是ShiroFilter的基础,包括维护filter列表、请求路径到过滤器链的映射和代理原过滤器链,从而让shiro的过滤器先执行。

ShiroFilter使用FilterChainManager代理原过滤器链

ShiroFilter是shiro的入口点,当请求路径到达ShiroFilter,shiro根据请求的路径,使用FilterChainManager代理原过滤器链,让请求先经过shiro的过滤器链,再执行原过滤器链。

先来看一下shiroFilter的继承关系。

shiroFilter继承自AbstractShiroFilter,并继承了OncePerRequestFilter,该过滤器用来实现一次请求只经过一个过滤器链。

    private static final class SpringShiroFilter extends AbstractShiroFilter {
        // 将FilterChainResolver传递进去
        protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
            super();
            if (webSecurityManager == null) {
                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
            }
            setSecurityManager(webSecurityManager);
            if (resolver != null) {
                setFilterChainResolver(resolver);
            }
        }
    }

FilterChainResolver本质上就是使用FilterChainManager来实现代理原过滤器链,可以看作是FilterChainManager的一层包装。

shiroFilter代码很少,主要继承了AbstractShiroFilter。OncePerRequestFilter过滤器主要实现一次请求只经过一个过滤器链,并调用doFilterInternal方法来具体实现过滤功能:

doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException   //该方法由子类实现

AbstractShiroFilter实现了doFilterInternal方法,代码如下:

protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
            throws ServletException, IOException {

        Throwable t = null;

        try {
            final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
            final ServletResponse response = prepareServletResponse(request, servletResponse, chain);

            final Subject subject = createSubject(request, response);

            //noinspection unchecked
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    updateSessionLastAccessTime(request, response);
                    // 重点:执行代理过滤器链
                    executeChain(request, response, chain);
                    return null;
                }
            });
        } 
        ...//省略代码,不影响阅读
    }

protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
            throws IOException, ServletException {
        // 使用FilterChainResolver来获取代理过滤器链
        FilterChain chain = getExecutionChain(request, response, origChain);
        // 执行代理过滤器链,由上一篇可知,会先执行shiro的过滤器链,然后执行原过滤器链
        chain.doFilter(request, response);
}

 AbstractShiroFilter.getExecutionChain

    protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
        FilterChain chain = origChain;

        FilterChainResolver resolver = getFilterChainResolver();
        if (resolver == null) {
            log.debug("No FilterChainResolver configured.  Returning original FilterChain.");
            return origChain;
        }
        // 会调用FilterChainManager来获取代理过滤器链
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            log.trace("Resolved a configured FilterChain for the current request.");
            chain = resolved;
        } else {
            log.trace("No FilterChain configured for the current request.  Using the default.");
        }

        return chain;
    }

 由上可知,AbstractShiroFilter会调用FilterChainResolver的getChain()方法。而ShiroFilterFactoryBean(在下一篇讲),在创建ShiroFilter实例的时候,使用的是PathMatchingFilterChainResolver。

 PathMatchingFilterChainResolver.getChain()方法如下:

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }

        String requestURI = getPathWithinApplication(request);

        // 遍历filterChainManager的过滤器链名称,看请求路径是否和过滤器链匹配
        for (String pathPattern : filterChainManager.getChainNames()) {

            // 如果请求路径和filterChainManager中的过滤器链名称匹配,则获取该名称对应的过滤器链
            if (pathMatches(pathPattern, requestURI)) {
                if (log.isTraceEnabled()) {
                    log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "].  " +
                            "Utilizing corresponding filter chain...");
                }
                // 最终调用filterChainManager.proxy来获取代理过滤器链
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }

        return null;
    }

 由此验证了我们开始说的,shiroFilter最终会使用FilterChainManager来获取代理器链,从而先执行shiro的过滤器链,然后再执行原过滤器链。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值