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)
}
}