|
| 1 | +[[servlet-authentication-securitycontextholder]] |
| 2 | += SecurityContextHolder |
| 3 | + |
| 4 | +:figures: images/servlet/authentication/architecture |
| 5 | + |
| 6 | +At the heart of Spring Security's authentication model is the `SecurityContextHolder`. |
| 7 | +It contains the <<servlet-authentication-securitycontext>>. |
| 8 | + |
| 9 | +image::{figures}/securitycontextholder.png[] |
| 10 | + |
| 11 | +The `SecurityContextHolder` is where Spring Security stores the details of who is <<authentication,authenticated>>. |
| 12 | +Spring Security does not care how the `SecurityContextHolder` is populated. |
| 13 | +If it contains a value, then it is used as the currently authenticated user. |
| 14 | + |
| 15 | +The simplest way to indicate a user is authenticated is to set the `SecurityContextHolder` directly. |
| 16 | + |
| 17 | +.Setting `SecurityContextHolder` |
| 18 | +==== |
| 19 | +[source,java] |
| 20 | +---- |
| 21 | +SecurityContext context = SecurityContextHolder.createEmptyContext(); // <1> |
| 22 | +Authentication authentication = |
| 23 | + new TestingAuthenticationToken("username", "password", "ROLE_USER"); // <2> |
| 24 | +context.setAuthentication(authentication); |
| 25 | +
|
| 26 | +SecurityContextHolder.setContext(context); // <3> |
| 27 | +---- |
| 28 | +==== |
| 29 | + |
| 30 | +<1> We start by creating an empty `SecurityContext`. |
| 31 | +It is important to create a new `SecurityContext` instance instead of using `SecurityContextHolder.getContext().setAuthentication(authentication)` to avoid race conditions across multiple threads. |
| 32 | +<2> Next we create a new <<servlet-authentication-authentication,`Authentication`>> object. |
| 33 | +Spring Security does not care what type of `Authentication` implementation is set on the `SecurityContext`. |
| 34 | +Here we use `TestingAuthenticationToken` because it is very simple. |
| 35 | +A more common production scenario is `UsernamePasswordAuthenticationToken(userDetails, password, authorities)`. |
| 36 | +<3> Finally, we set the `SecurityContext` on the `SecurityContextHolder`. |
| 37 | +Spring Security will use this information for <<authorization>>. |
| 38 | + |
| 39 | +If you wish to obtain information about the authenticated principal, you can do so by accessing the `SecurityContextHolder`. |
| 40 | + |
| 41 | +.Access Currently Authenticated User |
| 42 | +==== |
| 43 | +[source,java] |
| 44 | +---- |
| 45 | +SecurityContext context = SecurityContextHolder.getContext(); |
| 46 | +Authentication authentication = context.getAuthentication(); |
| 47 | +String username = authentication.getName(); |
| 48 | +Object principal = authentication.getPrincipal(); |
| 49 | +Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); |
| 50 | +---- |
| 51 | +==== |
| 52 | + |
| 53 | +// FIXME: add links to HttpServletRequest.getRemoteUser() and @CurrentSecurityContext @AuthenticationPrincipal |
| 54 | + |
| 55 | +By default the `SecurityContextHolder` uses a `ThreadLocal` to store these details, which means that the `SecurityContext` is always available to methods in the same thread of execution, even if the `SecurityContext` is not explicitly passed around as an argument to those methods. |
| 56 | +Using a `ThreadLocal` in this way is quite safe if care is taken to clear the thread after the present principal's request is processed. |
| 57 | +Spring Security's <<servlet-filterchainproxy,FilterChainProxy>> ensures that the `SecurityContext` is always cleared. |
| 58 | + |
| 59 | +Some applications aren't entirely suitable for using a `ThreadLocal`, because of the specific way they work with threads. |
| 60 | +For example, a Swing client might want all threads in a Java Virtual Machine to use the same security context. |
| 61 | +`SecurityContextHolder` can be configured with a strategy on startup to specify how you would like the context to be stored. |
| 62 | +For a standalone application you would use the `SecurityContextHolder.MODE_GLOBAL` strategy. |
| 63 | +Other applications might want to have threads spawned by the secure thread also assume the same security identity. |
| 64 | +This is achieved by using `SecurityContextHolder.MODE_INHERITABLETHREADLOCAL`. |
| 65 | +You can change the mode from the default `SecurityContextHolder.MODE_THREADLOCAL` in two ways. |
| 66 | +The first is to set a system property, the second is to call a static method on `SecurityContextHolder`. |
| 67 | +Most applications won't need to change from the default, but if you do, take a look at the JavaDoc for `SecurityContextHolder` to learn more. |
0 commit comments