mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-24 19:28:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| [[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)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| =====
 |