In‑Depth Analysis of Spring Security Authentication Process and Core Components
This article provides a comprehensive walkthrough of Spring Security’s authentication mechanism, detailing the filter chain, core security components, and the underlying source‑code flow—from UsernamePasswordAuthenticationFilter through AuthenticationManager, ProviderManager, and DaoAuthenticationProvider—illustrated with code examples and diagrams.
In enterprise Java projects, Spring Security and Apache Shiro are the two most popular authentication and authorization frameworks; Spring Security offers richer features and community support but has a steeper learning curve, making it the preferred choice for medium‑to‑large applications.
What is Spring Security? According to the official description, Spring Security is a framework that provides both authentication and authorization for Java applications and can be easily extended to meet custom requirements.
The core responsibilities of Spring Security are authentication (verifying a user’s identity) and authorization (checking whether the user has permission to access resources).
Core Filters
Spring Security implements authentication through a chain of filters. The default DefaultSecurityFilterChain is created as follows:
public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
this.requestMatcher = requestMatcher;
this.filters = new ArrayList(filters);
}Key filters in the chain include:
SecurityContextPersistenceFilter : loads or creates a SecurityContext at the start of a request and stores it back to the session at the end.
UsernamePasswordAuthenticationFilter : extracts username and password from a login form and creates a UsernamePasswordAuthenticationToken for validation.
AnonymousAuthenticationFilter : generates an anonymous token when no authenticated principal is present.
ExceptionTranslationFilter : converts authentication and access‑denied exceptions into appropriate HTTP responses.
Core Components
The main security objects are:
SecurityContextHolder : a static holder that provides access to the current SecurityContext.
SecurityContext : stores the Authentication object for the current request.
Authentication : represents the authentication token (e.g., username/password, OAuth token) and exposes methods such as getAuthorities(), getCredentials(), getDetails(), getPrincipal(), and isAuthenticated().
AuthenticationManager : the top‑level interface with a single method Authentication authenticate(Authentication authentication) that delegates to a list of AuthenticationProvider s.
Typical usage:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SecurityUserDetails userDetails = (SecurityUserDetails) authentication.getPrincipal();Spring Security supports three storage strategies for the SecurityContext:
MODE_THREADLOCAL – stored in the current thread.
MODE_INHERITABLETHREADLOCAL – child threads inherit the parent’s context.
MODE_GLOBAL – shared across all threads.
Authentication Process
The user submits credentials; UsernamePasswordAuthenticationFilter intercepts the request and creates an unauthenticated UsernamePasswordAuthenticationToken.
The token is passed to the AuthenticationManager (usually a ProviderManager).
The manager iterates over its AuthenticationProvider list. The first provider that supports the token type (e.g., DaoAuthenticationProvider) performs the actual verification. DaoAuthenticationProvider retrieves user details via a UserDetailsService, checks account status, and validates the password with a PasswordEncoder.
On success, an authenticated UsernamePasswordAuthenticationToken containing the UserDetails is returned and stored in the SecurityContextHolder.
UsernamePasswordAuthenticationFilter
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
private String usernameParameter = "username";
private String passwordParameter = "password";
private boolean postOnly = true;
// ... constructor sets AntPathRequestMatcher("/login", "POST")
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) username = "";
if (password == null) password = "";
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
}UsernamePasswordAuthenticationToken
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private Object credentials;
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(false);
}
public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
// getters and setters omitted for brevity
}AuthenticationManager and ProviderManager
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}The default implementation ProviderManager loops through a list of AuthenticationProvider s:
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
Authentication result = null;
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) continue;
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
} catch (AuthenticationException ex) {
lastException = ex;
}
}
if (result == null && lastException != null) throw lastException;
return result;
}AuthenticationProvider and DaoAuthenticationProvider
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
} DaoAuthenticationProvideris the most common provider. It retrieves a UserDetails from a UserDetailsService and validates the password:
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException("UserDetailsService returned null");
}
return loadedUser;
}
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getCredentials() == null) {
throw new BadCredentialsException("Bad credentials");
}
String presentedPassword = authentication.getCredentials().toString();
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
throw new BadCredentialsException("Bad credentials");
}
}Summary
The article walks through the complete Spring Security authentication flow, from the initial HTTP request intercepted by UsernamePasswordAuthenticationFilter, through token creation, delegation to AuthenticationManager, provider selection, user detail retrieval, password verification, and finally storing the authenticated token in SecurityContextHolder. Understanding the relationships among AuthenticationManager, ProviderManager, and various AuthenticationProvider s is essential for customizing authentication mechanisms.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
政采云技术
ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
