Caching UserDetails
Spring Security provides support for caching UserDetails with CachingUserDetailsService.
Alternatively, you can use Spring Framework’s @Cacheable annotation.
In either case, you will need to disable credential erasure in order to validate passwords retrieved from the cache.
CachingUserDetailsService
Spring Security’s CachingUserDetailsService implements 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:
CachingUserDetailsService @Bean-
Java
-
Kotlin
@Bean
public CachingUserDetailsService cachingUserDetailsService(UserCache userCache) {
UserDetailsService delegate = ...;
CachingUserDetailsService service = new CachingUserDetailsService(delegate);
service.setUserCache(userCache);
return service;
}
@Bean
fun cachingUserDetailsService(userCache: UserCache): CachingUserDetailsService {
val delegate: UserDetailsService = ...
val service = CachingUserDetailsService(delegate)
service.userCache = userCache
return service
}
@Cacheable
An alternative approach would be to use Spring Framework’s @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-
Java
-
Kotlin
@Service
public class MyCustomUserDetailsImplementation implements UserDetailsService {
@Override
@Cacheable
public UserDetails loadUserByUsername(String username) {
// some logic here to get the actual user details
return userDetails;
}
}
@Service
class MyCustomUserDetailsImplementation : UserDetailsService {
@Cacheable
override fun loadUserByUsername(username: String): UserDetails {
// some logic here to get the actual user details
return userDetails
}
}
Disable Credential Erasure
Whether you use CachingUserDetailsService or @Cacheable, you will need to disable 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:
AuthenticationManager-
Java
-
Kotlin
@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);
}
}
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)
}
}