Spring Security provides a number of optional integrations with Spring MVC. This section covers the integration in further detail.
Note | |
---|---|
As of Spring Security 4.0, |
To enable Spring Security integration with Spring MVC add the @EnableWebSecurity
annotation to your configuration.
Note | |
---|---|
Spring Security provides the configuration using Spring MVC’s WebMvcConfigurerAdapter. This means that if you are using more advanced options, like integrating with |
Spring Security provides AuthenticationPrincipalArgumentResolver
which can automatically resolve the current Authentication.getPrincipal()
for Spring MVC arguments. By using Section 34.1, “@EnableWebMvcSecurity” you will automatically have this added to your Spring MVC configuration. If you use XML based configuraiton, you must add this yourself.
Once AuthenticationPrincipalArgumentResolver
is properly configured, you can be entirely decoupled from Spring Security in your Spring MVC layer.
Consider a situation where a custom UserDetailsService
that returns an Object
that implements UserDetails
and your own CustomUser
Object
. The CustomUser
of the currently authenticated user could be accessed using the following code:
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal; // ... @RequestMapping("/messages/inbox") public ModelAndView findMessagesForUser() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); CustomUser custom = (CustomUser) authentication == null ? null : authentication.getPrincipal(); // .. find messags for this user and return them ... }
As of Spring Security 3.2 we can resolve the argument more directly by adding an annotation. For example:
@RequestMapping("/messages/inbox") public ModelAndView findMessagesForUser(@AuthenticationPrincipal CustomUser customUser) { // .. find messags for this user and return them ... }
We can further remove our dependency on Spring Security by making @AuthenticationPrincipal
a meta annotation on our own annotation. Below we demonstrate how we could do this on an annotation named @CurrentUser
.
Note | |
---|---|
It is important to realize that in order to remove the dependency on Spring Security, it is the consuming application that would create |
@Target({ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @AuthenticationPrincipal public @interface CurrentUser {}
Now that @CurrentUser
has been specified, we can use it to signal to resolve our CustomUser
of the currently authenticated user. We have also isolated our dependency on Spring Security to a single file.
@RequestMapping("/messages/inbox") public ModelAndView findMessagesForUser(@CurrentUser CustomUser customUser) { // .. find messags for this user and return them ... }
Spring Web MVC 3.2+ has excellent support for Asynchronous Request Processing. With no additional configuration, Spring Security will automatically setup the SecurityContext
to the Thread
that executes a Callable
returned by your controllers. For example, the following method will automatically have its Callable
executed with the SecurityContext
that was available when the Callable
was created:
@RequestMapping(method=RequestMethod.POST) public Callable<String> processUpload(final MultipartFile file) { return new Callable<String>() { public Object call() throws Exception { // ... return "someView"; } }; }
Associating SecurityContext to Callable’s | |
---|---|
More technically speaking, Spring Security integrates with |
There is no automatic integration with a DeferredResult
that is returned by controllers.
This is because DeferredResult
is processed by the users and thus there is no way of automatically integrating with it.
However, you can still use Concurrency Support to provide transparent integration with Spring Security.
Spring Security will automatically include the CSRF Token within forms that use the Spring MVC form tag. For example, the following JSP:
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:form="http://www.springframework.org/tags/form" version="2.0"> <jsp:directive.page language="java" contentType="text/html" /> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <!-- ... --> <c:url var="logoutUrl" value="/logout"/> <form:form action="${logoutUrl}" method="post"> <input type="submit" value="Log out" /> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form:form> <!-- ... --> </html> </jsp:root>
Will output HTML that is similar to the following:
<!-- ... --> <form action="/context/logout" method="post"> <input type="submit" value="Log out"/> <input type="hidden" name="_csrf" value="f81d4fae-7dec-11d0-a765-00a0c91e6bf6"/> </form> <!-- ... -->
Spring Security provides CsrfTokenResolver
which can automatically resolve the current CsrfToken
for Spring MVC arguments.
By using @EnableWebSecurity you will automatically have this added to your Spring MVC configuration.
If you use XML based configuraiton, you must add this yourself.
Once CsrfTokenResolver
is properly configured, you can expose the CsrfToken
to your static HTML based application.
@RestController public class CsrfController { @RequestMapping("/csrf") public CsrfToken csrf(CsrfToken token) { return token; } }
It is important to keep the CsrfToken
a secret from other domains.
This means if you are using Cross Origin Sharing (CORS), you should NOT expose the CsrfToken
to any external domains.