mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-11-03 16:18:48 +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)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								=====
							 |