Spring Security’s Servlet support is based on Servlet filters. The image of this article is from the Spring website

The following figure shows typical handler layering for a single HTTP request:

  • The client sends the request to the application, and the container creates a FilterChain containing filters and servlets that should process the HttpServletRequest based on the path of the request URL.
  • In a Spring MVC application, the Servlet is an instance of DispatcherServlet.
  • A Servlet can handle up to one HttpServletRequest and HttpServletResponse.
  • However, you can use more than one Filter.
  • Each layer of filter can modify the HttpServletRequest or HttpServletResponse used by downstream filters and servlets

The power of the Filter comes from the FilterChain passed to it:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // do something before the rest of the application
    chain.doFilter(request, response); // invoke the rest of the application
    // do something after the rest of the application
}
Copy the code

Note: Because Filters only affect downstream Filters and servlets, the order in which each Filter is called is important.


DelegatingFilterProxy

Spring provides a filter implementation called DelegatingFilterProxy that allows bridging between the lifecycle of the Servlet container and Spring’s ApplicationContext. The Servlet container allows it to use its own standard registration filter, but it is not aware of the beans defined by Spring. The DelegatingFilterProxy can register the Filter through the standard Servlet container mechanism and delegate all the work to the Spring Bean that implements the Filter.

The addition of DelegatingFilterProxy causes the instance of Bean Filter0 to work properly.

DelegatingFilterProxy

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // Lazily get Filter that was registered as a Spring Bean
    // For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
    Filter delegate = getFilterBean(someBeanName);
    // delegate work to the Spring Bean
    delegate.doFilter(request, response);
}
Copy the code

FilterChainProxy

Spring Security’s Servlet support is included with FilterChainProxy. FilterChainProxy is a special Filter provided by Spring Security that allows delegating to many Filter instances through the SecurityFilterChain. Since FilterChainProxy is a Bean, it is usually encapsulated in DelegatingFilterProxy.


SecurityFilterChain

SecurityFilterChain is used by FilterChainProxy to determine which Spring security filter should be invoked for this request.

Note:

Security filters in the SecurityFilterChain are usually beans, but they are registered with the FilterChainProxy rather than the DelegatingFilterProxy. FilterChainProxy provides many advantages for registering directly with a Servlet container or DelegatingFilterProxy. First, it provides a starting point for all Of Spring Security’s Servlet support. So, if you’re troubleshooting Spring Security’s Servlet support, adding a tuner pilot to FilterChainProxy is a good place to start.

In addition, it provides more flexibility in determining when the SecurityFilterChain should be called. In the Servlet container, the filter is invoked only based on the URL. However, FilterChainProxy can make use of the RequestMatcher interface to determine the invocation based on anything in the HttpServletRequest.

As shown in the figure above, FilterChainProxy decides which SecurityFilterChain should be used. Only the first matching SecurityFilterChain will be called. If the requested URL is/API /messages/, it will first match the/API /** mode of SecurityFilterChaing, so only SecurityFilterChaing0 will be called, Even though it also matches SecurityFilterChainN. If a /messages is requested, it will not match the/API /** mode of SecurityFilterChaing0, so FilterChainProxy will continue to try each SecurityFilterChain. SecurityFilterChainN will be called assuming no other SecurityFilterChain instances match.


Security Filters

The SecurityFilter is inserted into FilterChainProxy through the SecurityFilterChain API. The order of filters is important. You usually don’t need to know the order of Spring Security’s Filters. But sometimes it’s good to know the order:

The order is as follows:

  • ChannelProcessingFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

Handling Security Exceptions

  • ExceptionTranslationFilter allows AccessDeniedException and AuthenticationException into the HTTP response.
  • ExceptionTranslationFilter as a security filters are inserted into the named FilterChainProxy.

  1. First of all, ExceptionTranslationFilter by calling the FilterChain. DoFilter (request, response) to wake the rest of the application.

  2. If the user is not authenticated or AuthenticationException, then authentication is enabled:

    • Remove SecurityContextHolder
    • HttpServletRequest is stored in RequestCache. When the user successfully authenticates, the original request is played back using RequestCache
    • AuthenticationEntryPoint is used to request credentials from the client. For example, it might redirect to a login page or send a www-Authenticate header.
  3. Otherwise, access is denied if it is an AccessDeniedException. Call AccessDeniedHandler to handle denied access.

ExceptionTranslationFilter pseudo code is as follows:

try {
    filterChain.doFilter(request, response); 
} catch (AccessDeniedException | AuthenticationException ex) {
    if(! authenticated || exinstanceof AuthenticationException) {
        startAuthentication(); 
    } else{ accessDenied(); }}Copy the code