shiro框架源码解析与改造(五)---SpringShiroFilter

这个类继承AbstractShiroFilter ,我在这里对notFilter字段做了实现,在shiro域中划了一块方外之地,减少了Subject的创建。

private static final class SpringShiroFilter extends AbstractShiroFilter {
        private Set<String> notFilters=new HashSet<>();
        protected PatternMatcher pathMatcher = new AntPathMatcher();

        protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver, Set<String> notFilters) {
            if(webSecurityManager == null) {
                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
            } else {
                this.setSecurityManager(webSecurityManager);
                this.notFilters=notFilters;
                if(resolver != null) {
                    this.setFilterChainResolver(resolver);
                }

            }
        }

        @Override
        protected boolean shouldNotFilter(ServletRequest request) throws ServletException {
            Set<String> notFilters=this.notFilters;
            if (notFilters!=null){
                Iterator iterator = notFilters.iterator();

                String path;
                do {
                    if(!iterator.hasNext()) {
                        return false;
                    }
                    path = (String)iterator.next();
                } while(!this.pathsMatch(path, request));
                return true;
            }
            return super.shouldNotFilter(request);
        }
        protected boolean pathsMatch(String path, ServletRequest request) {
            String requestURI = this.getPathWithinApplication(request);
            log.trace("Attempting to match pattern '{}' with current requestURI '{}'...");
            return this.pathsMatch(path, requestURI);
        }
        protected String getPathWithinApplication(ServletRequest request) {
            return WebUtils.getPathWithinApplication(WebUtils.toHttp(request));
        }
        protected boolean pathsMatch(String pattern, String path) {
            return this.pathMatcher.matches(pattern, path);
        }
        @Override
        public void destroy() {

        }
    }

在父类中有2个成员变量:
private WebSecurityManager securityManager;
private FilterChainResolver filterChainResolver;

doFilter方法是拦截的起点。

     public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        String alreadyFilteredAttributeName = this.getAlreadyFilteredAttributeName();

        if(request.getAttribute(alreadyFilteredAttributeName) != null) {
            filterChain.doFilter(request, response);
        }else if(this.isEnabled(request, response) && !this.shouldNotFilter(request)) {
            request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);

            try {
                this.doFilterInternal(request, response, filterChain);
            } finally {
                request.removeAttribute(alreadyFilteredAttributeName);
            }
        } else {
            filterChain.doFilter(request, response);
        }
    }

实际调用doFilterInternal方法。

this.doFilterInternal(request, response, filterChain);

 protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException {
        Throwable t = null;

        try {
            final ServletRequest request = this.prepareServletRequest(servletRequest, servletResponse, chain);
            final ServletResponse response = this.prepareServletResponse(request, servletResponse, chain);
//            System.out.println(WebUtils.getRequestUri((HttpServletRequest) request));
            Subject subject = this.createSubject(request, response);
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    AbstractShiroFilter.this.updateSessionLastAccessTime(request, response);
                    AbstractShiroFilter.this.executeChain(request, response, chain);
                    return null;
                }
            });
        } catch (ExecutionException var8) {
            t = var8.getCause();
        } catch (Throwable var9) {
            t = var9;
        }

        if(t != null) {
            if(t instanceof ServletException) {
                throw (ServletException)t;
            } else if(t instanceof IOException) {
                throw (IOException)t;
            } else {
                String msg = "Filtered request failed.";
                throw new ServletException(msg, t);
            }
        }
    }

执行拦截链前对request 和response做了包装,然后创建了Subject,在subect的回调函数中执行了filterChain。

 protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException {
        FilterChain chain = this.getExecutionChain(request, response, origChain);
        chain.doFilter(request, response);
    }


 protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
        FilterChain chain = origChain;
        FilterChainResolver resolver = this.getFilterChainResolver();
        if(resolver == null) {
            log.debug("No FilterChainResolver configured.  Returning original FilterChain.");
            return origChain;
        } else {
            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;
        }
    }

上面的filterChainResolver就是上文解析的那个类。

下面的代码是为了保证每一个过滤器在一次请求中只执行一次。

 String alreadyFilteredAttributeName = this.getAlreadyFilteredAttributeName();
 request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
 request.removeAttribute(alreadyFilteredAttributeName);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
web.xml配置 因为我们是与spring进行集成的,而spring的基本就是web项目的xml文件。所以我们在web.xml中配置shiros的过滤拦截。正常情况下,我们需要将shirofilter配置在所有的filter前面,当然和encodingFilter这个filter是不区分前后的。因为两者互相不影响的。spring-shiro.xml 这里我们将来看看spring-shiro.xml的配置,这里我采取倒叙的方式讲解,我觉的倒叙更加的有助于我们理解代码。首先我们还记得在web.xml中配置的那个filter吧,名字shiroFilter,对spring-shiro.xml配置文件就是通过这个filter展开的。首先我们在web.xml配置的过滤器实际上是配置ShiroFilterFactoryBean,所以在这里需要将ShiroFilterFactoryBean定义为shiroFilter <!-- Shiro的核心安全接口,这个属性是必须的 --> <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 --> <!-- 登录成功后要跳转的连接 --> <!-- 用户访问未对其授权的资源时,所显示的连接 --> <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp --> <!-- Shiro连接约束配置,即过滤链的定义 --> <!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 --> <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 --> <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 --> <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter --> /statics/**=anon /login.html=anon /sys/schedule.html=perms[sys:schedule:save] /sys/login=anon /captcha.jpg=anon /**=authc

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值