即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

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

编程语言 RobertoHuang 18℃ 0评论

最近在学习安全框架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 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);
    }
}

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

转载请注明:CodingBlog » Spring Security4.0.3源码解析之FilterChainProxy执行过程解析

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情