This section discusses the high-level architecture of Spring Security in servlet-based applications.
A brief
description of filters
Spring Security's servlet support is based on Filter
servlet instances, so it's useful to first look at the role of Filter
in general. The figure below
shows a typical layered structure of handlers for a single HTTP request.
![](https://cdn.codegym.cc/images/article/9e804fc3-08e4-48d9-a91e-70414583d5b8/256.jpeg)
The client
sends a
request to the application, and the container creates a FilterChain
, which contains instances of a
Filter
and a Servlet
that should process a HttpServletRequest
based on the
request URI path. In a Spring MVC application, Servlet
is an instance of DispatcherServlet
.
Only one Servlet
can handle one HttpServletRequest
and HttpServletResponse
.
However, you can use more than one Filter
to:
Prevent calls to downstream
Filter
orServlet
. In this case,Filter
typically recordsHttpServletResponse
.Changes to
HttpServletRequest
orHttpServletResponse
used by subsequentFilter
andServlet
The power of Filter
depends on FilterChain
, which is passed into it.
FilterChain
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// do something before executing the rest of the application
chain.doFilter(request, response) ;// invoke the rest of the application
// do something after the rest of the application is executed
}
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
// do something before executing the rest of the application
chain.doFilter(request, response)// invoke the rest of the application
// do something after the rest of the application has executed
}
Because the Filter
only affects the underlying Filter
and
Servlet
, the order in which each Filter
is called is extremely important.
DelegatingFilterProxy
Spring provides an implementation of Filter
titled DelegatingFilterProxy
, which allows you to establish a bridge between the
lifecycle of a servlet container and ApplicationContext
from Spring. The servlet container allows you
to register Filter
instances using its own standards, but it does not know about the beans defined by
Spring. DelegatingFilterProxy
can be registered through standard servlet container mechanisms, but
delegates all the work to the Spring bean that implements Filter
.
Here is how DelegatingFilterProxy
is used
fits into a schema with Filter
and FilterChain
instances.
![](https://cdn.codegym.cc/images/article/9f02cafc-c0e6-456f-a7d3-917f21a01d1f/256.jpeg)
DelegatingFilterProxy
looks up Bean Filter0 in ApplicationContext
and then calls Bean
Filter0. The pseudo code for DelegatingFilterProxy
is shown below.
DelegatingFilterProxy
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// In deferred mode, we get the filter that was registered as a Spring bean
// For the example in DelegatingFilterProxy, the delegate is instance Bean Filter0
Filter delegate = getFilterBean(someBeanName);
// delegate the work to the Spring bean delegate.doFilter(request, response);
}
fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
// In deferred mode, we get the filter that was registered as a Spring bean
// For the example in DelegatingFilterProxy, the delegate is an instance of Bean Filter0
val delegate: Filter = getFilterBean(someBeanName)
// delegate work with the Spring bean delegate.doFilter(request, response)
}
Another advantage of DelegatingFilterProxy
is that it allows you to defer the search for
instances of Filter
beans. This is important because the container needs to register
Filter
instances before running the container. However, Spring typically uses ContextLoaderListener
to load Spring beans, which only happens after Filter
instances have been registered.
FilterChainProxy
Servlet Facilities in Spring Security they are contained in FilterChainProxy
.
FilterChainProxy
is a specialized Filter
provided by Spring Security that allows you to
delegate authority to multiple Filter
instances via <SecurityFilterChain
. Since FilterChainProxy
is a bean, it is usually wrapped in DelegatingFilterProxy.
![](https://cdn.codegym.cc/images/article/c8845bc7-7293-46e7-9c40-e06ca170869b/512.jpeg)
SecurityFilterChain
SecurityFilterChain
is used by FilterChainProxy
to determine which Filter
from Spring Security should be called for a given request.
![](https://cdn.codegym.cc/images/article/5e5fbf12-3ca5-4520-9f1a-79fed6a641c3/512.jpeg)
Security filters in SecurityFilterChain
are usually beans, but they are registered in FilterChainProxy
instead of DelegatingFilterProxy
. FilterChainProxy
provides several advantages over
registering directly with the servlet container or DelegatingFilterProxy. First, it provides the starting point for
all servlet support in Spring Security. For this reason, if you are trying to troubleshoot Spring Security's servlet
support, a good place to start is by adding a debug point to FilterChainProxy
.
Secondly, because
FilterChainProxy
is central to the use of Spring Security, it can perform tasks that are not
considered optional. For example, it cleans up SecurityContext
to avoid memory leaks. It also uses
HttpFirewall
from Spring Security to protect applications from certain types of attacks.
It also
provides greater flexibility in determining when to call SecurityFilterChain
. In a servlet container,
Filter
instances are called based on the URL only. However, FilterChainProxy
can determine
the call based on anything in HttpServletRequest
using the RequestMatcher
interface.
In fact, FilterChainProxy
can be used to determine which SecurityFilterChain
should be
used. This allows you to provide completely separate configuration for different parts of your application.
![](https://cdn.codegym.cc/images/article/44d4dade-4b63-462d-9b0a-82fb02ca8644/512.jpeg)
In the
picture with several SecurityFilterChain, the FilterChainProxy
instance decides which SecurityFilterChain
should be used. Only the first matching SecurityFilterChain
will be called. If the URL /api/messages/
is requested, it will first be matched against the pattern SecurityFilterChain0
via /api/**
,
so only SecurityFilterChain0
will be called, even if it also matches SecurityFilterChainn
.
If the /messages/
URL is requested, it will not be matched against the
SecurityFilterChain0
pattern via /api/**
, so FilterChainProxy
will continue to iterate over each SecurityFilterChain
. It is assumed that other instances of
SecurityFilterChain
that match SecurityFilterChainn
will not be called.
Note that in SecurityFilterChain0
only three instances of Filter
are
configured. However, there are four Filter
s configured in the
SecurityFilterChainn
. It is important to note that each SecurityFilterChain
can
be unique and configured in isolation. In fact, SecurityFilterChain
can have zero Filter
instances if the application wants Spring Security to ignore certain requests.
Security Filters
Spring Security filters are added to FilterChainProxy via the SecurityFilterChain API. The order of
Filter
instances matters. Typically there is no need to know the order of Filter
in Spring
Security. However, in some cases it is useful to know what order they are in.
The following is a complete ordered list of Spring Security filters:
ForceEagerSessionCreationFilter
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
Security exception handling
ExceptionTranslationFilter
allows conversion AccessDeniedException
and AuthenticationException
in HTTP responses.
ExceptionTranslationFilter
is added to FilterChainProxy in quality of one of the security filters.
![](https://cdn.codegym.cc/images/article/a38c12b1-2fb2-46b6-a706-cababcf33ff4/512.jpeg)
1 First
ExceptionTranslationFilter
accessesFilterChain.doFilter(request, response)
to call the rest of the application.2 If the user is not authenticated or an
AuthenticationException
occurs, then run authentication procedure.TheSecurityContextHolder is cleared
HttpServletRequest
is saved inRequestCache
. Once the user is successfully authenticated,RequestCache
will be used to replay the original request.AuthenticationEntryPoint
is used to request credentials client data. For example, it could redirect to a login page or send aWWW-Authenticate
header.
3 Otherwise, if
AccessDeniedException
occurs, access will be denied.AccessDeniedHandle
r
is called to handle access denial.
If the application does not throw an AccessDeniedException
or AuthenticationException
, then the ExceptionTranslationFilter
does nothing.
The pseudocode for the ExceptionTranslationFilter
looks something like this:
try {
filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException ex) {
if (!authenticated || ex instanceof AuthenticationException) {
startAuthentication();
} else {
accessDenied();
}
}
- From the brief description of
Filter
instances, you may recall that callingFilterChain.doFilter(request, response)
is equivalent to calling the rest of the application. This means that if another part of the application (e.g.FilterSecurityInterceptor
or security method) throws anAuthenticationException
orAccessDeniedException
, then those exceptions will be caught and handled at this stage. - If the user is not authenticated or an
AuthenticationException
is thrown, then run the authentication procedure. - Otherwise access will be denied