docs
Authentication management services that process authentication requests through chains of authentication providers. Includes AuthenticationManager, ProviderManager, reactive alternatives, and authentication provider implementations.
Core Capabilities:
AuthenticationManager processes authentication requests and returns fully authenticated objectsProviderManager iterates through AuthenticationProvider chain until one succeedsAuthenticationEventPublisher (success/failure events)ObservationAuthenticationManager for metrics/tracingReactiveAuthenticationManager and DelegatingReactiveAuthenticationManagerKey Interfaces and Classes:
AuthenticationManager - Functional interface: authenticate(Authentication) returns authenticated token or throws exceptionAuthenticationProvider - Processes specific authentication types (supports(Class), authenticate(Authentication))ProviderManager - Iterates through provider list, supports parent manager fallbackReactiveAuthenticationManager - Returns Mono<Authentication> for non-blocking authenticationDelegatingReactiveAuthenticationManager - Iterates through reactive managersReactiveAuthenticationManagerAdapter - Adapts synchronous manager to reactive APIAuthenticationManagerResolver<C> - Resolves manager from context (e.g., HTTP request)ObservationAuthenticationManager - Wraps manager with Micrometer observation supportDefault Behaviors:
ProviderManager tries providers in order until one authenticates or all failsetEraseCredentialsAfterAuthentication(true))setShouldPublishResult())Threading Model:
Mono<Authentication> for non-blocking executionLifecycle:
ProviderManager implements InitializingBean (validates configuration)setAuthenticationEventPublisher() (optional)Exceptions:
AuthenticationException - Base exception for authentication failuresBadCredentialsException - Invalid credentialsDisabledException - Account disabledLockedException - Account lockedAccountExpiredException - Account expiredCredentialsExpiredException - Credentials expiredProviderNotFoundException - No provider supports authentication typeAuthenticationServiceException - Service error during authenticationEdge Cases:
Mono.error(AuthenticationException) instead of throwingIllegalArgumentException if registry is nullProcesses an authentication request and returns a fully authenticated object including credentials.
package org.springframework.security.authentication;
@FunctionalInterface
interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}Method Details:
authenticate(Authentication) - Attempts to authenticate the passed Authentication object. Returns a fully authenticated Authentication with isAuthenticated() == true on success. Throws AuthenticationException if authentication fails.Return Behavior:
Authentication (including granted authorities) if successfulDisabledException if account is disabledLockedException if account is lockedBadCredentialsException if credentials are invalidUsage Pattern:
AuthenticationManager authManager = // ... configured manager
UsernamePasswordAuthenticationToken authRequest =
UsernamePasswordAuthenticationToken.unauthenticated("user", "password");
try {
Authentication result = authManager.authenticate(authRequest);
// Result is fully authenticated: result.isAuthenticated() == true
SecurityContextHolder.getContext().setAuthentication(result);
log.info("Authentication successful for user: {}", result.getName());
} catch (BadCredentialsException e) {
log.error("Invalid credentials: {}", e.getMessage());
} catch (DisabledException e) {
log.error("Account disabled: {}", e.getMessage());
} catch (LockedException e) {
log.error("Account locked: {}", e.getMessage());
} catch (AuthenticationException e) {
log.error("Authentication failed: {}", e.getMessage());
}Critical Implementation Notes:
isAuthenticated() == trueProcesses specific Authentication implementation types.
package org.springframework.security.authentication;
interface AuthenticationProvider {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
boolean supports(Class<?> authentication);
}Method Details:
authenticate(Authentication) - Performs authentication with the same contract as AuthenticationManager.authenticate(). May return null if this provider cannot authenticate (abstain behavior).supports(Class) - Returns true if this provider supports the indicated Authentication class.Return Behavior:
Authentication if this provider can authenticatenull if this provider cannot authenticate (abstain - not an error)AuthenticationException if authentication fails (e.g., bad credentials)Usage Pattern:
public class CustomAuthenticationProvider implements AuthenticationProvider {
private final CustomAuthenticationService authService;
private final UserDetailsService userDetailsService;
public CustomAuthenticationProvider(
CustomAuthenticationService authService,
UserDetailsService userDetailsService) {
this.authService = authService;
this.userDetailsService = userDetailsService;
}
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Check if this provider can handle this authentication type
if (!supports(authentication.getClass())) {
return null; // Abstain - let other providers try
}
String username = authentication.getName();
String password = authentication.getCredentials().toString();
// Custom authentication logic
if (!authService.authenticate(username, password)) {
throw new BadCredentialsException("Invalid credentials");
}
// Load user details
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// Return fully authenticated token
return UsernamePasswordAuthenticationToken.authenticated(
userDetails, password, userDetails.getAuthorities());
}
@Override
public boolean supports(Class<?> authentication) {
return UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication);
}
}Critical Implementation Notes:
supports() should be fast (no I/O operations)null from authenticate() is valid (abstain behavior)Reactive authentication manager for non-blocking authentication.
package org.springframework.security.authentication;
interface ReactiveAuthenticationManager {
Mono<Authentication> authenticate(Authentication authentication);
}Method Details:
authenticate(Authentication) - Attempts to authenticate the passed Authentication object reactively. Returns Mono<Authentication> that emits authenticated token on success or error signal on failure.Return Behavior:
Mono<Authentication> that emits fully authenticated token on successMono.error(AuthenticationException) on failureUsage Pattern:
ReactiveAuthenticationManager authManager = // ... configured manager
UsernamePasswordAuthenticationToken authRequest =
UsernamePasswordAuthenticationToken.unauthenticated("user", "password");
authManager.authenticate(authRequest)
.doOnSuccess(auth -> {
log.info("Authentication successful: {}", auth.getName());
// Set in reactive security context
ReactiveSecurityContextHolder.withAuthentication(auth)
.subscribe();
})
.doOnError(BadCredentialsException.class, e -> {
log.error("Invalid credentials: {}", e.getMessage());
})
.doOnError(DisabledException.class, e -> {
log.error("Account disabled: {}", e.getMessage());
})
.doOnError(AuthenticationException.class, e -> {
log.error("Authentication failed: {}", e.getMessage());
})
.subscribe();Critical Implementation Notes:
Mono (never null)Mono.error()Resolves an AuthenticationManager from a context object.
package org.springframework.security.authentication;
interface AuthenticationManagerResolver<C> {
AuthenticationManager resolve(C context);
}Method Details:
resolve(C) - Returns an AuthenticationManager based on the provided context. May return null if no manager can be resolved.Usage Pattern:
// Resolve different authentication managers based on request path
AuthenticationManagerResolver<HttpServletRequest> resolver = request -> {
String path = request.getRequestURI();
if (path.startsWith("/api/admin")) {
return adminAuthenticationManager;
} else if (path.startsWith("/api/internal")) {
return internalAuthenticationManager;
} else if (path.startsWith("/api/public")) {
return publicAuthenticationManager;
}
return defaultAuthenticationManager;
};
// Usage in filter
AuthenticationManager manager = resolver.resolve(request);
if (manager != null) {
Authentication result = manager.authenticate(authRequest);
}Critical Implementation Notes:
Reactive version of AuthenticationManagerResolver.
package org.springframework.security.authentication;
interface ReactiveAuthenticationManagerResolver<C> {
Mono<ReactiveAuthenticationManager> resolve(C context);
}Method Details:
resolve(C) - Returns a Mono that emits an appropriate ReactiveAuthenticationManager for the context. May emit null if no manager can be resolved.Usage Pattern:
ReactiveAuthenticationManagerResolver<ServerWebExchange> resolver = exchange -> {
String path = exchange.getRequest().getPath().value();
if (path.startsWith("/api/admin")) {
return Mono.just(adminReactiveAuthManager);
} else if (path.startsWith("/api/public")) {
return Mono.just(publicReactiveAuthManager);
}
return Mono.just(defaultReactiveAuthManager);
};
// Usage in reactive filter
resolver.resolve(exchange)
.flatMap(manager -> manager.authenticate(authRequest))
.subscribe();Iterates through a list of AuthenticationProvider instances to perform authentication.
package org.springframework.security.authentication;
class ProviderManager implements AuthenticationManager, MessageSourceAware,
InitializingBean {
ProviderManager(List<AuthenticationProvider> providers);
ProviderManager(List<AuthenticationProvider> providers,
AuthenticationManager parent);
ProviderManager(AuthenticationProvider... providers);
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
List<AuthenticationProvider> getProviders();
void setMessageSource(MessageSource messageSource);
void setAuthenticationEventPublisher(
AuthenticationEventPublisher eventPublisher);
void setEraseCredentialsAfterAuthentication(boolean eraseCredentials);
void setParent(AuthenticationManager parent);
AuthenticationManager getParent();
boolean isEraseCredentialsAfterAuthentication();
}Constructor Details:
ProviderManager(List<AuthenticationProvider>) - Creates a manager with the specified providers.ProviderManager(List<AuthenticationProvider>, AuthenticationManager) - Creates a manager with providers and a parent manager to try if no provider authenticates.ProviderManager(AuthenticationProvider...) - Varargs constructor for convenience.Method Details:
authenticate(Authentication) - Iterates through providers until one successfully authenticates or all fail. If no provider authenticates and parent manager exists, tries parent. Throws ProviderNotFoundException if no provider supports the authentication type and no parent exists.getProviders() - Returns the list of configured providers (unmodifiable).setAuthenticationEventPublisher(AuthenticationEventPublisher) - Sets the event publisher for authentication events (optional).setEraseCredentialsAfterAuthentication(boolean) - Controls whether credentials are erased after successful authentication (default: true).setParent(AuthenticationManager) - Sets a parent authentication manager to try if no providers can authenticate (Spring Security 7.0.0: can only be set via constructor).getParent() - Returns the parent manager (may be null).Authentication Flow:
provider.supports(authentication.getClass())provider.authenticate(authentication)ProviderNotFoundExceptionUsage Pattern:
// Configure provider manager
List<AuthenticationProvider> providers = Arrays.asList(
new DaoAuthenticationProvider(), // Try first
new RememberMeAuthenticationProvider("key"), // Try second
new AnonymousAuthenticationProvider("key") // Try third
);
ProviderManager providerManager = new ProviderManager(providers);
providerManager.setEraseCredentialsAfterAuthentication(true);
providerManager.setAuthenticationEventPublisher(
new DefaultAuthenticationEventPublisher(applicationEventPublisher));
// Use the provider manager
try {
Authentication result = providerManager.authenticate(authRequest);
// Success - result is fully authenticated
} catch (ProviderNotFoundException e) {
// No provider could handle this authentication type
} catch (AuthenticationException e) {
// Authentication failed
}Complete Configuration Example:
@Configuration
public class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder,
ApplicationEventPublisher eventPublisher) {
// Create DAO authentication provider
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
daoProvider.setUserDetailsService(userDetailsService);
daoProvider.setPasswordEncoder(passwordEncoder);
// Create remember-me provider
RememberMeAuthenticationProvider rememberMeProvider =
new RememberMeAuthenticationProvider("remember-me-secret-key");
// Create anonymous provider
AnonymousAuthenticationProvider anonymousProvider =
new AnonymousAuthenticationProvider("anonymous-key");
// Build provider list (order matters - first matching provider wins)
List<AuthenticationProvider> providers = Arrays.asList(
daoProvider, // Primary authentication
rememberMeProvider, // Remember-me authentication
anonymousProvider // Anonymous authentication
);
// Create provider manager with parent (optional)
AuthenticationManager parentManager = createParentManager();
ProviderManager providerManager = new ProviderManager(providers, parentManager);
// Configure credential erasure
providerManager.setEraseCredentialsAfterAuthentication(true);
// Configure event publishing
DefaultAuthenticationEventPublisher eventPublisherImpl =
new DefaultAuthenticationEventPublisher(eventPublisher);
providerManager.setAuthenticationEventPublisher(eventPublisherImpl);
return providerManager;
}
private AuthenticationManager createParentManager() {
// Optional parent manager for fallback
return new ProviderManager(/* fallback providers */);
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}Critical Implementation Notes:
ProviderNotFoundException if no provider supports authentication typeIterates through ReactiveAuthenticationManager instances reactively.
package org.springframework.security.authentication;
class DelegatingReactiveAuthenticationManager
implements ReactiveAuthenticationManager {
DelegatingReactiveAuthenticationManager(
List<ReactiveAuthenticationManager> delegates);
DelegatingReactiveAuthenticationManager(
ReactiveAuthenticationManager... delegates);
Mono<Authentication> authenticate(Authentication authentication);
}Constructor Details:
DelegatingReactiveAuthenticationManager(List) - Creates a manager with the specified delegates.DelegatingReactiveAuthenticationManager(ReactiveAuthenticationManager...) - Varargs constructor.Authentication Flow:
delegate.authenticate(authentication)Mono.empty()Usage Pattern:
List<ReactiveAuthenticationManager> managers = Arrays.asList(
new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService),
new ReactiveAuthenticationManagerAdapter(rememberMeAuthenticationManager)
);
DelegatingReactiveAuthenticationManager authManager =
new DelegatingReactiveAuthenticationManager(managers);
authManager.authenticate(authRequest)
.switchIfEmpty(Mono.error(new ProviderNotFoundException("No manager could authenticate")))
.subscribe(auth -> log.info("Authenticated: {}", auth.getName()));Critical Implementation Notes:
Mono.empty() if no delegate authenticates (not an error)Adapts a synchronous AuthenticationManager to reactive API.
package org.springframework.security.authentication;
class ReactiveAuthenticationManagerAdapter
implements ReactiveAuthenticationManager {
ReactiveAuthenticationManagerAdapter(AuthenticationManager authenticationManager);
Mono<Authentication> authenticate(Authentication authentication);
}Usage Pattern:
AuthenticationManager syncManager = new ProviderManager(providers);
ReactiveAuthenticationManager reactiveManager =
new ReactiveAuthenticationManagerAdapter(syncManager);
reactiveManager.authenticate(authRequest)
.subscribe(auth -> log.info("Authenticated: {}", auth.getName()));Critical Implementation Notes:
Mono.fromCallable()Wraps an AuthenticationManager to add Micrometer observation/metrics support.
package org.springframework.security.authentication;
class ObservationAuthenticationManager implements AuthenticationManager {
ObservationAuthenticationManager(ObservationRegistry observationRegistry,
AuthenticationManager delegate);
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}Usage Pattern:
ObservationRegistry observationRegistry = ObservationRegistry.create();
AuthenticationManager delegate = new ProviderManager(providers);
ObservationAuthenticationManager authManager =
new ObservationAuthenticationManager(observationRegistry, delegate);
// All authentication attempts will be observed
try {
Authentication result = authManager.authenticate(authRequest);
// Observation includes success metrics
} catch (AuthenticationException e) {
// Observation includes failure metrics
}Critical Implementation Notes:
Reactive version with observation support.
package org.springframework.security.authentication;
class ObservationReactiveAuthenticationManager
implements ReactiveAuthenticationManager {
ObservationReactiveAuthenticationManager(ObservationRegistry observationRegistry,
ReactiveAuthenticationManager delegate);
Mono<Authentication> authenticate(Authentication authentication);
}Context object for authentication observations containing request, result, and error information.
package org.springframework.security.authentication;
class AuthenticationObservationContext extends Observation.Context {
AuthenticationObservationContext();
Authentication getAuthenticationRequest();
void setAuthenticationRequest(Authentication authenticationRequest);
Authentication getAuthenticationResult();
void setAuthenticationResult(Authentication authenticationResult);
Throwable getError();
void setError(Throwable error);
}Naming convention for authentication observations.
package org.springframework.security.authentication;
interface AuthenticationObservationConvention
extends ObservationConvention<AuthenticationObservationContext> {
@Override
default boolean supportsContext(Observation.Context context);
}Abstract base class for reactive authentication using user details.
package org.springframework.security.authentication;
abstract class AbstractUserDetailsReactiveAuthenticationManager
implements ReactiveAuthenticationManager, InitializingBean {
AbstractUserDetailsReactiveAuthenticationManager();
Mono<Authentication> authenticate(Authentication authentication);
void setUserDetailsChecker(UserDetailsChecker userDetailsChecker);
void setPostAuthenticationChecks(UserDetailsChecker postAuthenticationChecks);
protected abstract Mono<UserDetails> retrieveUser(String username);
}Method Details:
authenticate(Authentication) - Performs authentication using user details retrieved reactively.setUserDetailsChecker(UserDetailsChecker) - Sets pre-authentication checks (account status).setPostAuthenticationChecks(UserDetailsChecker) - Sets post-authentication checks.retrieveUser(String) - Abstract method to retrieve user details reactively.Usage Pattern:
public class CustomReactiveAuthenticationManager
extends AbstractUserDetailsReactiveAuthenticationManager {
private final ReactiveUserDetailsService userDetailsService;
public CustomReactiveAuthenticationManager(
ReactiveUserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Override
protected Mono<UserDetails> retrieveUser(String username) {
return userDetailsService.findByUsername(username)
.switchIfEmpty(Mono.error(new UsernameNotFoundException(username)));
}
}Reactive authentication manager using ReactiveUserDetailsService.
package org.springframework.security.authentication;
class UserDetailsRepositoryReactiveAuthenticationManager
extends AbstractUserDetailsReactiveAuthenticationManager {
UserDetailsRepositoryReactiveAuthenticationManager(
ReactiveUserDetailsService userDetailsService);
void setPasswordEncoder(PasswordEncoder passwordEncoder);
void setUserDetailsPasswordService(
ReactiveUserDetailsPasswordService userDetailsPasswordService);
void setCompromisedPasswordChecker(
ReactiveCompromisedPasswordChecker compromisedPasswordChecker);
void setHideUserNotFoundExceptions(boolean hideUserNotFoundExceptions);
}Method Details:
ReactiveUserDetailsService for loading users.setPasswordEncoder(PasswordEncoder) - Sets the password encoder (default: delegates to password in database).setUserDetailsPasswordService(ReactiveUserDetailsPasswordService) - Service for updating passwords after authentication.setCompromisedPasswordChecker(ReactiveCompromisedPasswordChecker) - Checker for compromised passwords.setHideUserNotFoundExceptions(boolean) - Controls whether to hide user not found exceptions (default: true).Usage Pattern:
ReactiveUserDetailsService userDetailsService =
new MapReactiveUserDetailsService(user1, user2);
UserDetailsRepositoryReactiveAuthenticationManager authManager =
new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
authManager.setPasswordEncoder(PasswordEncoderFactories.createDelegatingPasswordEncoder());
authManager.setHideUserNotFoundExceptions(true);
authManager.authenticate(authRequest)
.subscribe(auth -> log.info("User authenticated: {}", auth.getName()));Publishes authentication success and failure events.
package org.springframework.security.authentication;
interface AuthenticationEventPublisher {
void publishAuthenticationSuccess(Authentication authentication);
void publishAuthenticationFailure(AuthenticationException exception,
Authentication authentication);
}Method Details:
publishAuthenticationSuccess(Authentication) - Publishes a success event.publishAuthenticationFailure(AuthenticationException, Authentication) - Publishes a failure event.Usage Pattern:
public class CustomAuthenticationEventPublisher implements AuthenticationEventPublisher {
private final ApplicationEventPublisher eventPublisher;
public CustomAuthenticationEventPublisher(
ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
@Override
public void publishAuthenticationSuccess(Authentication authentication) {
eventPublisher.publishEvent(
new AuthenticationSuccessEvent(authentication));
}
@Override
public void publishAuthenticationFailure(
AuthenticationException exception,
Authentication authentication) {
eventPublisher.publishEvent(
new AbstractAuthenticationFailureEvent(authentication, exception) {});
}
}Default implementation publishing Spring application events.
package org.springframework.security.authentication;
class DefaultAuthenticationEventPublisher
implements AuthenticationEventPublisher, ApplicationEventPublisherAware {
DefaultAuthenticationEventPublisher();
DefaultAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
void publishAuthenticationSuccess(Authentication authentication);
void publishAuthenticationFailure(AuthenticationException exception,
Authentication authentication);
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
void setDefaultAuthenticationFailureEvent(
Class<? extends AbstractAuthenticationFailureEvent> defaultAuthenticationFailureEvent);
void setAdditionalExceptionMappings(
Map<Class<? extends AuthenticationException>,
Class<? extends AbstractAuthenticationFailureEvent>> additionalExceptionMappings);
}Method Details:
setDefaultAuthenticationFailureEvent(Class) - Sets the default failure event class for unmapped exceptions.setAdditionalExceptionMappings(Map) - Maps specific exception types to event types.Usage Pattern:
DefaultAuthenticationEventPublisher eventPublisher =
new DefaultAuthenticationEventPublisher(applicationEventPublisher);
// Map custom exceptions to events
Map<Class<? extends AuthenticationException>,
Class<? extends AbstractAuthenticationFailureEvent>> mappings = new HashMap<>();
mappings.put(CustomAuthException.class, CustomAuthFailureEvent.class);
mappings.put(BadCredentialsException.class, AuthenticationFailureBadCredentialsEvent.class);
eventPublisher.setAdditionalExceptionMappings(mappings);
// Use with provider manager
ProviderManager providerManager = new ProviderManager(providers);
providerManager.setAuthenticationEventPublisher(eventPublisher);Critical Implementation Notes:
ProviderManager to publish eventsCreates authentication details objects from a context (typically an HTTP request).
package org.springframework.security.authentication;
interface AuthenticationDetailsSource<C, T> {
T buildDetails(C context);
}Method Details:
buildDetails(C) - Creates a details object from the provided context. May return null.Usage Pattern:
// Custom details source
public class CustomAuthenticationDetailsSource
implements AuthenticationDetailsSource<HttpServletRequest, CustomDetails> {
@Override
public CustomDetails buildDetails(HttpServletRequest request) {
return new CustomDetails(
request.getRemoteAddr(),
request.getHeader("User-Agent"),
request.getSession() != null ? request.getSession().getId() : null,
request.getHeader("X-Forwarded-For")
);
}
}
// Usage
AuthenticationDetailsSource<HttpServletRequest, CustomDetails> detailsSource =
new CustomAuthenticationDetailsSource();
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken("user", "password");
authRequest.setDetails(detailsSource.buildDetails(request));Checks user account status before or after authentication.
package org.springframework.security.core.userdetails;
interface UserDetailsChecker {
void check(UserDetails toCheck);
}Method Details:
check(UserDetails) - Examines user details and throws AccountStatusException if account is not valid.Usage Pattern:
public class CustomUserDetailsChecker implements UserDetailsChecker {
@Override
public void check(UserDetails toCheck) {
if (!toCheck.isEnabled()) {
throw new DisabledException("Account is disabled");
}
if (!toCheck.isAccountNonExpired()) {
throw new AccountExpiredException("Account has expired");
}
if (!toCheck.isAccountNonLocked()) {
throw new LockedException("Account is locked");
}
if (!toCheck.isCredentialsNonExpired()) {
throw new CredentialsExpiredException("Credentials have expired");
}
}
}Default implementation checking standard account flags.
package org.springframework.security.authentication;
class AccountStatusUserDetailsChecker implements UserDetailsChecker {
AccountStatusUserDetailsChecker();
void check(UserDetails user);
}Implementation:
DisabledException if !user.isEnabled()AccountExpiredException if !user.isAccountNonExpired()LockedException if !user.isAccountNonLocked()CredentialsExpiredException if !user.isCredentialsNonExpired()Usage Pattern:
UserDetailsChecker accountStatusChecker = new AccountStatusUserDetailsChecker();
try {
accountStatusChecker.check(userDetails);
// Account is valid
} catch (DisabledException e) {
log.error("Account is disabled: {}", userDetails.getUsername());
} catch (LockedException e) {
log.error("Account is locked: {}", userDetails.getUsername());
} catch (AccountExpiredException e) {
log.error("Account expired: {}", userDetails.getUsername());
} catch (CredentialsExpiredException e) {
log.error("Credentials expired: {}", userDetails.getUsername());
}Caching decorator for UserDetailsService.
package org.springframework.security.authentication;
class CachingUserDetailsService implements UserDetailsService {
CachingUserDetailsService(UserDetailsService delegate);
UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException;
UserCache getUserCache();
void setUserCache(UserCache userCache);
}Method Details:
UserDetailsService to cache.setUserCache(UserCache) - Sets the cache implementation (default: NullUserCache).Usage Pattern:
UserDetailsService delegate = new JdbcDaoImpl(dataSource);
UserCache cache = new SpringCacheBasedUserCache(cacheManager.getCache("users"));
CachingUserDetailsService cachingService = new CachingUserDetailsService(delegate);
cachingService.setUserCache(cache);
// First call loads from database
UserDetails user1 = cachingService.loadUserByUsername("john");
// Second call loads from cache
UserDetails user2 = cachingService.loadUserByUsername("john");Critical Implementation Notes: