Skip to content

Add documentation for CachingUserDetailsService #14263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,55 @@
import org.springframework.util.Assert;

/**
* Implementation of {@link UserDetailsService} that utilizes caching through a
* {@link UserCache}
* <p>
* If a null {@link UserDetails} instance is got from calling
* {@link UserCache#getUserFromCache(String)} to the {@link UserCache} got from
* {@link #getUserCache()}, the user load is deferred to the {@link UserDetailsService}
* provided during construction. Otherwise, the instance got from cache is returned.
* <p>
* It is initialized with a {@link NullUserCache} by default, so it's strongly recommended
* setting your own {@link UserCache} using {@link #setUserCache(UserCache)}, otherwise,
* the delegate will be called every time.
* <p>
* Utilize this class by defining {@link org.springframework.context.annotation.Bean} that
* encapsulates an actual implementation of {@link UserDetailsService} and set an
* {@link UserCache}.
* </p>
* For example: <pre>{@code
* &#64;Bean
* public CachingUserDetailsService cachingUserDetailsService(UserDetailsService delegate,
* UserCache userCache) {
* CachingUserDetailsService service = new CachingUserDetailsService(delegate);
* service.setUserCache(userCache);
* return service;
* }
* }</pre>
*
* <p>
* However, a preferable approach would be to use
* {@link org.springframework.cache.annotation.Cacheable} in your
* {@link UserDetailsService#loadUserByUsername(String)} implementation to cache
* {@link UserDetails} by <code>username</code>, reducing boilerplate and setup, specially
* if you are already using cache in your application.
* </p>
*
* For example:
*
* <pre>{@code
* &#64;Service
* public class MyCustomUserDetailsImplementation implements UserDetailsService {

* &#64;Override
* &#64;Cacheable
* public UserDetails loadUserByUsername(String username) {
* //some logic here to get the actual user details
* return userDetails;
* }
* }
* }</pre>
*
* @author Luke Taylor
* @since 2.0
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[[servlet-authentication-cached]]
= CachingUserDetailsService

Spring Security's `CachingUserDetailsService` implements xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[UserDetailsService] offering support for caching authentication.

`CachingUserDetailsService` provides caching support for `UserDetails` by delegating the authentication process to the provided `UserDetailsService`. The result is then stored in a `UserCache` to reduce computation in subsequent calls.

Utilize this class by defining a `@Bean` of it that encapsulates a concrete implementation of `UserDetailsService` and set a `UserCache` to cache authenticated `UserDetails`.

For example:

[source,java]
----
@Bean
public CachingUserDetailsService cachingUserDetailsService(UserDetailsService delegate, UserCache userCache) {
CachingUserDetailsService service = new CachingUserDetailsService(delegate);
service.setUserCache(userCache);
return service;
}
----

However, a preferable approach would be to use `@Cacheable` in your `UserDetailsService.loadUserByUsername(String)` implementation to cache `UserDetails` by `username`, reducing boilerplate and setup, especially if you are already using cache in your application.

For example:

[source,java]
----
@Service
public class MyCustomUserDetailsImplementation implements UserDetailsService {

@Override
@Cacheable
public UserDetails loadUserByUsername(String username) {
// some logic here to get the actual user details
return userDetails;
}
}
----
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
= UserDetailsService

{security-api-url}org/springframework/security/core/userdetails/UserDetailsService.html[`UserDetailsService`] is used by xref:servlet/authentication/passwords/dao-authentication-provider.adoc#servlet-authentication-daoauthenticationprovider[`DaoAuthenticationProvider`] for retrieving a username, a password, and other attributes for authenticating with a username and password.
Spring Security provides xref:servlet/authentication/passwords/in-memory.adoc#servlet-authentication-inmemory[in-memory] and xref:servlet/authentication/passwords/jdbc.adoc#servlet-authentication-jdbc[JDBC] implementations of `UserDetailsService`.
Spring Security provides xref:servlet/authentication/passwords/in-memory.adoc#servlet-authentication-inmemory[in-memory], xref:servlet/authentication/passwords/jdbc.adoc#servlet-authentication-jdbc[JDBC], and xref:servlet/authentication/passwords/cached.adoc#servlet-authentication-cached[in-cache] implementations of `UserDetailsService`.

You can define custom authentication by exposing a custom `UserDetailsService` as a bean.
For example, the following listing customizes authentication, assuming that `CustomUserDetailsService` implements `UserDetailsService`:
Expand Down