Spring Security(二十九):9.4.1 ExceptionTranslationFilter
ExceptionTranslationFilter
is a Spring Security filter that has responsibility for detecting any Spring Security exceptions that are thrown. Such exceptions will generally be thrown by an AbstractSecurityInterceptor
, which is the main provider of authorization services. We will discuss AbstractSecurityInterceptor
in the next section, but for now we just need to know that it produces Java exceptions and knows nothing about HTTP or how to go about authenticating a principal. Instead the ExceptionTranslationFilter
offers this service, with specific responsibility for either returning error code 403 (if the principal has been authenticated and therefore simply lacks sufficient access - as per step seven above), or launching an AuthenticationEntryPoint
(if the principal has not been authenticated and therefore we need to go commence step three).
9.4.2 AuthenticationEntryPoint
The AuthenticationEntryPoint
is responsible for step three in the above list. As you can imagine, each web application will have a default authentication strategy (well, this can be configured like nearly everything else in Spring Security, but let’s keep it simple for now). Each major authentication system will have its own AuthenticationEntryPoint
implementation, which typically performs one of the actions described in step 3.
9.4.3 Authentication Mechanism
Once your browser submits your authentication credentials (either as an HTTP form post or HTTP header) there needs to be something on the server that "collects" these authentication details. By now we’re at step six in the above list. In Spring Security we have a special name for the function of collecting authentication details from a user agent (usually a web browser), referring to it as the "authentication mechanism". Examples are form-base login and Basic authentication. Once the authentication details have been collected from the user agent, an Authentication
"request" object is built and then presented to the AuthenticationManager
.
Authentication
object, it will deem the request valid, put the Authentication
into the SecurityContextHolder
, and cause the original request to be retried (step seven above). If, on the other hand, the AuthenticationManager
rejected the request, the authentication mechanism will ask the user agent to retry (step two above).9.4.4 Storing the SecurityContext between requests
Depending on the type of application, there may need to be a strategy in place to store the security context between user operations. In a typical web application, a user logs in once and is subsequently identified by their session Id. The server caches the principal information for the duration session. In Spring Security, the responsibility for storing the SecurityContext
between requests falls to the SecurityContextPersistenceFilter
, which by default stores the context as an HttpSession
attribute between HTTP requests. It restores the context to the SecurityContextHolder
for each request and, crucially, clears the SecurityContextHolder
when the request completes. You shouldn’t interact directly with the HttpSession
for security purposes. There is simply no justification for doing so - always use the SecurityContextHolder
instead.
SecurityContextPersistenceFilter
is included in the chain to make sure that the SecurityContextHolder
is cleared after each request.SecurityContext
instance will be shared between threads. Even though a ThreadLocal
is being used, it is the same instance that is retrieved from the HttpSession
for each thread. This has implications if you wish to temporarily change the context under which a thread is running. If you just use SecurityContextHolder.getContext()
, and call setAuthentication(anAuthentication)
on the returned context object, then the Authentication
object will change in all concurrent threads which share the same SecurityContext
instance. You can customize the behaviour of SecurityContextPersistenceFilter
to create a completely new SecurityContext
for each request, preventing changes in one thread from affecting another. Alternatively you can create a new instance just at the point where you temporarily change the context. The method SecurityContextHolder.createEmptyContext()
always returns a new context instance.