ServletContextHow to getFilterChainProxyFilter object of

As we all know, beans are stored in Spring’s Bean factory, and servlets, filters, and listeners are put into a ServletContext in a Web project.

See the image below, ServletContainerInitializer interface provides a onStartup () method, is used to the Servlet container startup dynamically register some object to the ServletContext.

The official explanation is that web.xml is not used for support. Provides ServletContainerInitializer, it can be through the SPI mechanism, when to start the web container, Will automatically to add appropriate jars found under the meta-inf/services to ServletContainerInitializer under the full path name of the file, its content is to implement the full path of a class ServletContainerInitializer, Instantiate them.

Through the figure below shows that the Spring framework through the SpringServletContainerInitializer class meta-inf configuration

SpringServletContainerInitializer ServletContainerInitializer interface is realized. Please note that this class of @ HandlesTypes annotations (WebApplicationInitializer. Class).

Based on Sevlet3.0 norms, the Servlet container calls onStartup () method, will be injected in the form of the Set Set WebApplicationInitializer subclasses (including interface and abstract class). Then in turn calls WebApplicationInitializer onStartup method of implementation class, to start the web. The effects of XML (add servlet listener instance to the ServletContext).

In the Spring Security AbstractSecurityWebApplicationInitializer is WebApplicationInitializer abstract subclass. When the following onStartup() method is executed, Invokes the insertSpringSecurityFilterChain () type is named FilterChainProxy name springSecurityFilterChain filter objects with DelegatingFilterProxy packaging, Then inject the ServletContext

Operation process

When a request arrives, the Dofilter () method of FilterChainProxy iterates through all the SecurityFilterChain urls and invokes the filters in the SecurityFilterChain for authentication or authorization.

public class FilterChainProxy extends GenericFilterBean {



    private final static String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");

    private List<SecurityFilterChain> filterChains;

    private FilterChainValidator filterChainValidator = new NullFilterChainValidator();

    private HttpFirewall firewall = new StrictHttpFirewall();



    public FilterChainProxy(a) {

    }



    public FilterChainProxy(SecurityFilterChain chain) {

        this(Arrays.asList(chain));

    }



    public FilterChainProxy(List<SecurityFilterChain> filterChains) {

        this.filterChains = filterChains;

    }



    @Override

    public void afterPropertiesSet(a) {

        filterChainValidator.validate(this);

    }



    @Override

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



        // Get a set of filter chains based on the current request

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

        // Requests go through the chain of filters

        vfc.doFilter(fwRequest, fwResponse);

    }



    / * *

* Obtain a chain of filters based on the Request

* /


    private List<Filter> getFilters(HttpServletRequest request) {

        for (SecurityFilterChain chain : filterChains) {

            if (chain.matches(request)) {

                return chain.getFilters();

            }

        }

        return null;

    }



    / * *

* Get a chain of filters based on the URL

* /


    public List<Filter> getFilters(String url) {

        return getFilters(firewall.getFirewalledRequest((new FilterInvocation(url, null)

                .getRequest())));

    }



    / * *

* Returns a filter chain

* /


    public List<SecurityFilterChain> getFilterChains(a) {

        return Collections.unmodifiableList(filterChains);

    }



    // Filter chain inner class

    private static class VirtualFilterChain implements FilterChain {

        private final FilterChain originalChain;

        private final List<Filter> additionalFilters;

        private final FirewalledRequest firewalledRequest;

        private final int size;

        private int currentPosition = 0;



        private VirtualFilterChain(FirewalledRequest firewalledRequest,

                FilterChain chain, List<Filter> additionalFilters)
 
{

            this.originalChain = chain;

            this.additionalFilters = additionalFilters;

            this.size = additionalFilters.size();

            this.firewalledRequest = firewalledRequest;

        }



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

            }

        }

    }



    public interface FilterChainValidator {

        void validate(FilterChainProxy filterChainProxy);

    }



    private static class NullFilterChainValidator implements FilterChainValidator {

        @Override

        public void validate(FilterChainProxy filterChainProxy) {

        }

    }



}

Copy the code


Series of articles: Spring Security in Plain English part 1: Explaining framework Principles in three Sentences

Spring Security (Part 2) : Creating FilterChainProxy

Spring Security (3) : How FilterChainProxy Works

Spring Security (part 4) : WebSecurity and HttpSecurity

Series of articles: Spring Security in Plain English, Part 5: The Authentication and Authorization Process