caching.adoc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. [[servlet-authentication-caching-user-details]]
  2. = Caching `UserDetails`
  3. Spring Security provides support for caching `UserDetails` with <<servlet-authentication-caching-user-details-service,`CachingUserDetailsService`>>.
  4. Alternatively, you can use Spring Framework's <<servlet-authentication-caching-user-details-cacheable,`@Cacheable`>> annotation.
  5. In either case, you will need to <<servlet-authentication-caching-user-details-credential-erasure,disable credential erasure>> in order to validate passwords retrieved from the cache.
  6. [[servlet-authentication-caching-user-details-service]]
  7. == `CachingUserDetailsService`
  8. Spring Security's `CachingUserDetailsService` implements xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[UserDetailsService] to provide support for caching `UserDetails`.
  9. `CachingUserDetailsService` provides caching support for `UserDetails` by delegating to the provided `UserDetailsService`.
  10. The result is then stored in a `UserCache` to reduce computation in subsequent calls.
  11. The following example simply defines a `@Bean` that encapsulates a concrete implementation of `UserDetailsService` and a `UserCache` for caching the `UserDetails`:
  12. .Provide a `CachingUserDetailsService` `@Bean`
  13. [tabs]
  14. ======
  15. Java::
  16. +
  17. [source,java,role="primary"]
  18. ----
  19. @Bean
  20. public CachingUserDetailsService cachingUserDetailsService(UserCache userCache) {
  21. UserDetailsService delegate = ...;
  22. CachingUserDetailsService service = new CachingUserDetailsService(delegate);
  23. service.setUserCache(userCache);
  24. return service;
  25. }
  26. ----
  27. Kotlin::
  28. +
  29. [source,kotlin,role="secondary"]
  30. ----
  31. @Bean
  32. fun cachingUserDetailsService(userCache: UserCache): CachingUserDetailsService {
  33. val delegate: UserDetailsService = ...
  34. val service = CachingUserDetailsService(delegate)
  35. service.userCache = userCache
  36. return service
  37. }
  38. ----
  39. ======
  40. [[servlet-authentication-caching-user-details-cacheable]]
  41. == `@Cacheable`
  42. An alternative approach would be to use Spring Framework's {spring-framework-reference-url}integration.html#cache-annotations-cacheable[`@Cacheable`] in your `UserDetailsService` implementation to cache `UserDetails` by `username`.
  43. The benefit to this approach is simpler configuration, especially if you are already using caching elsewhere in your application.
  44. The following example assumes caching is already configured, and annotates the `loadUserByUsername` with `@Cacheable`:
  45. .`UserDetailsService` annotated with `@Cacheable`
  46. [tabs]
  47. ======
  48. Java::
  49. +
  50. [source,java,role="primary"]
  51. ----
  52. @Service
  53. public class MyCustomUserDetailsImplementation implements UserDetailsService {
  54. @Override
  55. @Cacheable
  56. public UserDetails loadUserByUsername(String username) {
  57. // some logic here to get the actual user details
  58. return userDetails;
  59. }
  60. }
  61. ----
  62. Kotlin::
  63. +
  64. [source,kotlin,role="secondary"]
  65. ----
  66. @Service
  67. class MyCustomUserDetailsImplementation : UserDetailsService {
  68. @Cacheable
  69. override fun loadUserByUsername(username: String): UserDetails {
  70. // some logic here to get the actual user details
  71. return userDetails
  72. }
  73. }
  74. ----
  75. ======
  76. [[servlet-authentication-caching-user-details-credential-erasure]]
  77. == Disable Credential Erasure
  78. Whether you use <<servlet-authentication-caching-user-details-service,`CachingUserDetailsService`>> or <<servlet-authentication-caching-user-details-cacheable,`@Cacheable`>>, you will need to disable xref:servlet/authentication/architecture.adoc#servlet-authentication-providermanager-erasing-credentials[credential erasure] so that the `UserDetails` will contain a `password` to be validated when retrieved from the cache.
  79. The following example disables credential erasure for the global `AuthenticationManager` by configuring the `AuthenticationManagerBuilder` provided by Spring Security:
  80. .Disable credential erasure for the global `AuthenticationManager`
  81. [tabs]
  82. =====
  83. Java::
  84. +
  85. [source,java,role="primary"]
  86. ----
  87. @Configuration
  88. @EnableWebSecurity
  89. public class SecurityConfig {
  90. @Bean
  91. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  92. // ...
  93. return http.build();
  94. }
  95. @Bean
  96. public UserDetailsService userDetailsService() {
  97. // Return a UserDetailsService that caches users
  98. // ...
  99. }
  100. @Autowired
  101. public void configure(AuthenticationManagerBuilder builder) {
  102. builder.eraseCredentials(false);
  103. }
  104. }
  105. ----
  106. Kotlin::
  107. +
  108. [source,kotlin,role="secondary"]
  109. ----
  110. import org.springframework.security.config.annotation.web.invoke
  111. @Configuration
  112. @EnableWebSecurity
  113. class SecurityConfig {
  114. @Bean
  115. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  116. // ...
  117. return http.build()
  118. }
  119. @Bean
  120. fun userDetailsService(): UserDetailsService {
  121. // Return a UserDetailsService that caches users
  122. // ...
  123. }
  124. @Autowired
  125. fun configure(builder: AuthenticationManagerBuilder) {
  126. builder.eraseCredentials(false)
  127. }
  128. }
  129. ----
  130. =====