1. 程式人生 > >Spring Security的過濾鏈工作原理

Spring Security的過濾鏈工作原理

上一篇文章中提到了名為springSecurityFilterChain的bean在Spring容器中的註冊過程。它所代表的類即為org.springframework.security.web.FilterChainProxy.

所以所有的url請求實際上都會經過這個過濾器代理。讓我們檢視一下他的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);
        }
    }

由此可見,他會再次經過doFilterInternal   方法
    private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        FirewalledRequest fwRequest = firewall.getFirewalledRequest((HttpServletRequest) request);
        HttpServletResponse fwResponse = firewall.getFirewalledResponse((HttpServletResponse) response);
        這個getFilters方法得到的過濾器就是在進行配置檔案解析時,security元件註冊的一些過濾器
        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();

            chain.doFilter(fwRequest, fwResponse);

            return;
        }

        VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
        //請求轉入vfc的doFilter方法
       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();

                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);
            }
        }