Spring Security4.0.3源码分析之FilterChainProxy执行过程分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

最近在学习安全框架spring Security,想弄清楚其中实现的具体步骤,于是下定决心,研究一下Spring Security源码,这篇博客的目的是想把学习过程记录下来。学习过程中主要参考了http://dead-knight.iteye.com/blog/1511389大神的博客,然后在其基础上,进行更详细的说明

在类org.springframework.web.filter.DelegatingFilterProxy的doFilter方法中可以看到,过滤器执行流程实际上是让委托执行实际的doFilter操作

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized (this.delegateMonitor) {
                if (this.delegate == null) {
                    WebApplicationContext wac = findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
                    }
                    // 初始化springSecurityFilterChain,详解请移步2.3
                    this.delegate = initDelegate(wac);
                }
                delegateToUse = this.delegate;
            }
        }

        // 让委托执行实际的doFilter操作
        invokeDelegate(delegateToUse, request, response, filterChain);
    }

通过前面几篇博客的分析,我们也知道这里的delegateToUse实际上是org.springframework.security.web.FilterChainProxy

接下来看FilterChainProxy中的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);
                doFilterInternal(request, response, chain);
            } finally {
                SecurityContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        } else {
            doFilterInternal(request, response, chain);
        }
    }

    private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) request);
        HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);

        List<Filter> filters = getFilters(fwRequest);

        if (filters == null || filters.size() == 0) {
            if (logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(fwRequest) + (filters == null ? " has no matching filters" : " has an empty filter list"));
            }

            fwRequest.reset();
            // 执行默认过滤器如编码过滤器EncodingFilter,转换请求方式过滤器HiddenHttpMethodFilter等
            chain.doFilter(fwRequest, fwResponse);
            return;
        }

        // 把实际doFilter任务交给VirtualFilterChain处理 
        VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
        vfc.doFilter(fwRequest, fwResponse);
    }

    // VirtualFilterChain的doFilter方法
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        // 判断是否是最后一个过滤器
        if (currentPosition == size) {
            if (logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " reached end of additional filter chain; proceeding with original chain");
            }

            // Deactivate path stripping as we exit the security filter chain
            this.firewalledRequest.reset();

            // 执行Filter的doFilter操作
            originalChain.doFilter(request, response);
        } else {
            // 当前位置加一
            currentPosition++;

            // 根据当前位置从过滤器列表中取出一个Filter
            Filter nextFilter = additionalFilters.get(currentPosition - 1);

            if (logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(firewalledRequest) + " at position " + currentPosition + " of " + size + " in additional filter chain; firing Filter: '" + nextFilter.getClass().getSimpleName() + "'");
            }

            // 执行Filte r的doFilter操作
            // 把自身作为参数传递给doFilter方法,这样doFilter方法最后会调用VirtualFilterChain的doFilter方法,这样控制就又回到了VirtualFilterChain
            nextFilter.doFilter(request, response, this);
        }
    }

下一篇博客将介绍各个过滤器的具体功能


来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Security4.0.3源码分析之FilterChainProxy执行过程分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏