Spring secutiry 源码解析 (二) —— filter执行流程

想要查看 spring security 的filter流程是从何开始, 只需在application.yml文件配置:

debug: true

启动的时候在控制台应该能看到类似的信息:

Filter 'webMvcMetricsFilter' configured for use 
Filter 'requestContextFilter' configured for use
Filter 'hiddenHttpMethodFilter' configured for use
Filter 'characterEncodingFilter' configured for use
Filter 'httpTraceFilter' configured for use
Filter 'springSecurityFilterChain' configured for use

找到源码,打断点,我们会发现 filter的执行顺序并不是像日志打印的一样,但也不太重要,我们只需看它到底做了个啥,一般第一个打印的filter的确是第一个执行的, 看它的父类 OncePerRequestFilter 的 doFilter 方法:

@Override
    public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
            throw new ServletException("OncePerRequestFilter just supports HTTP requests");
        }
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
        boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;

        if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {

            // Proceed without invoking this filter...
            filterChain.doFilter(request, response);
        }
        else {
            // Do invoke this filter...
            request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
            try {
                doFilterInternal(httpRequest, httpResponse, filterChain);
            }
            finally {
                // Remove the "already filtered" request attribute for this request.
                request.removeAttribute(alreadyFilteredAttributeName);
            }
        }
    }

每个filter执行完都会把这个filter的全限定名称加".APPLIED" 放入request传递下去,所以我们只需看 else 条件, 走 doFilterInternal 方法(子类实现):

filterChain.doFilter(request, response);

最终是走 FilterChain 接口的 doFilter 方法(实现类 ApplicationFilterChain 实现), 当 filter 走到 DelegatingFilterProxy 后,就会进入到另一个子filter集合, 通过 FilterChainProxy 调用:

@Override
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();

                originalChain.doFilter(request, response);
            }
            else {
                currentPosition++;

                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() + "'");
                }

                nextFilter.doFilter(request, response, this);
            }

这里面的 additionalFilters 变量储存着所有通过 WebSecurityConfiguration 类配置加载的 filter 集合, 我们实际上配置security config加载的 filter 都在这里面,只需在这里打断点调试就行。

你可能感兴趣的:(Spring secutiry 源码解析 (二) —— filter执行流程)