123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- [[servlet-authentication-caching-user-details]]
- = Caching `UserDetails`
- Spring Security provides support for caching `UserDetails` with <<servlet-authentication-caching-user-details-service,`CachingUserDetailsService`>>.
- Alternatively, you can use Spring Framework's <<servlet-authentication-caching-user-details-cacheable,`@Cacheable`>> annotation.
- 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.
- [[servlet-authentication-caching-user-details-service]]
- == `CachingUserDetailsService`
- Spring Security's `CachingUserDetailsService` implements xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[UserDetailsService] to provide support for caching `UserDetails`.
- `CachingUserDetailsService` provides caching support for `UserDetails` by delegating to the provided `UserDetailsService`.
- The result is then stored in a `UserCache` to reduce computation in subsequent calls.
- The following example simply defines a `@Bean` that encapsulates a concrete implementation of `UserDetailsService` and a `UserCache` for caching the `UserDetails`:
- .Provide a `CachingUserDetailsService` `@Bean`
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Bean
- public CachingUserDetailsService cachingUserDetailsService(UserCache userCache) {
- UserDetailsService delegate = ...;
- CachingUserDetailsService service = new CachingUserDetailsService(delegate);
- service.setUserCache(userCache);
- return service;
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Bean
- fun cachingUserDetailsService(userCache: UserCache): CachingUserDetailsService {
- val delegate: UserDetailsService = ...
- val service = CachingUserDetailsService(delegate)
- service.userCache = userCache
- return service
- }
- ----
- ======
- [[servlet-authentication-caching-user-details-cacheable]]
- == `@Cacheable`
- 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`.
- The benefit to this approach is simpler configuration, especially if you are already using caching elsewhere in your application.
- The following example assumes caching is already configured, and annotates the `loadUserByUsername` with `@Cacheable`:
- .`UserDetailsService` annotated with `@Cacheable`
- [tabs]
- ======
- Java::
- +
- [source,java,role="primary"]
- ----
- @Service
- public class MyCustomUserDetailsImplementation implements UserDetailsService {
- @Override
- @Cacheable
- public UserDetails loadUserByUsername(String username) {
- // some logic here to get the actual user details
- return userDetails;
- }
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- @Service
- class MyCustomUserDetailsImplementation : UserDetailsService {
- @Cacheable
- override fun loadUserByUsername(username: String): UserDetails {
- // some logic here to get the actual user details
- return userDetails
- }
- }
- ----
- ======
- [[servlet-authentication-caching-user-details-credential-erasure]]
- == Disable Credential Erasure
- 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.
- The following example disables credential erasure for the global `AuthenticationManager` by configuring the `AuthenticationManagerBuilder` provided by Spring Security:
- .Disable credential erasure for the global `AuthenticationManager`
- [tabs]
- =====
- Java::
- +
- [source,java,role="primary"]
- ----
- @Configuration
- @EnableWebSecurity
- public class SecurityConfig {
- @Bean
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- // ...
- return http.build();
- }
- @Bean
- public UserDetailsService userDetailsService() {
- // Return a UserDetailsService that caches users
- // ...
- }
- @Autowired
- public void configure(AuthenticationManagerBuilder builder) {
- builder.eraseCredentials(false);
- }
- }
- ----
- Kotlin::
- +
- [source,kotlin,role="secondary"]
- ----
- import org.springframework.security.config.annotation.web.invoke
- @Configuration
- @EnableWebSecurity
- class SecurityConfig {
- @Bean
- fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
- // ...
- return http.build()
- }
- @Bean
- fun userDetailsService(): UserDetailsService {
- // Return a UserDetailsService that caches users
- // ...
- }
- @Autowired
- fun configure(builder: AuthenticationManagerBuilder) {
- builder.eraseCredentials(false)
- }
- }
- ----
- =====
|