security-context-holder.adoc 4.5 KB

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