Article directory
Preface
After understanding the core components of SpringSecurity through the above , you can further understand its authentication implementation process.
Authentication entry (filter)
The authentication logic handled in SpringSecurity is UsernamePasswordAuthenticationFilter
implemented in this filter. UsernamePasswordAuthenticationFilter
Inherited from AbstractAuthenticationProcessingFilter
this parent class.
There is UsernamePasswordAuthenticationFilter
no doFilter method implemented, so the authentication logic needs to look AbstractAuthenticationProcessingFilter
at the doFilter method first.
The core code above is
Authentication authenticationResult = attemptAuthentication(request, response);
attemptAuthentication
The function of the method is to obtain Authentication
the object corresponding to the authentication process. Enter it UsernamePasswordAuthenticationFilter
to view the specific implementation.
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
username = (username != null) ? username : "";
username = username.trim();
String password = obtainPassword(request);
password = (password != null) ? password : "";
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
The meaning of the above code is very clear
- This method only supports requests submitted through POST.
- Get account and password
- Obtained
UsernamePasswordAuthenticationToken
the object through account password - Set request details
AuthenticationManager
Complete the authentication operation by
An object appears in the above logicAuthenticationManager
Authentication Manager
AuthenticationManager
The interface defines a method authenticate
to handle authentication requests.
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
Authenticator description
AuthenticationManager
The default implementation of is ProviderManager
, and the operation implemented in the method is to loop through the member ProviderManager
variables . If one of the functions returns true, the function authentication will be called . If the authentication is successful, the entire authentication process will end. If it is unsuccessful, continue to use the next suitable one for authentication. As long as one authentication is successful, the authentication is successful.authenticate
List<AuthenticationProvider> providers
providers
AuthenticationProvider
supports
AuthenticationProvider
authenticate
AuthenticationProvider
The default implementation provided in the current environment is
Implementation of the default authenticator
AbstractUserDetailsAuthenticationProvider
Authentication method to enter
Then enter retrieveUser
the method. The specific implementation is that DaoAuthenticationProvider
our getUserDetailsService
customized UserServiceImpl
object will be obtained, that is, our customized authentication method will be used.
@Override
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
prepareTimingAttackProtection();
try {
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
if (loadedUser == null) {
throw new InternalAuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
catch (UsernameNotFoundException ex) {
mitigateAgainstTimingAttack(authentication);
throw ex;
}
catch (InternalAuthenticationServiceException ex) {
throw ex;
}
catch (Exception ex) {
throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
}
}
If the account exists, password verification will start, but a check will still be completed before password verification.
Then there is the specific password verification
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
Specific verification logic
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// 密码为空
if (authentication.getCredentials() == null) {
this.logger.debug("Failed to authenticate since no credentials provided");
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
// 获取表单提交的密码
String presentedPassword = authentication.getCredentials().toString();
// 表单提交的密码和数据库查询的密码 比较是否相对
if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
this.logger.debug("Failed to authenticate since password does not match stored value");
throw new BadCredentialsException(this.messages
.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
}
}
The above logic will be processed through the corresponding password encoder. If it is non-encrypted, it will be processed through NoOpPasswordEncoder.
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return rawPassword.toString().equals(encodedPassword);
}
If there is encryption processing, select the corresponding encryption object to process, such as the BCryptPasswordEncoder used to get started with SpringSecurity.
Summarize
Spring Security certification process:
- The request first goes to the filter, which is used to verify that the system sets filters for restricted resources.
- After the request is received by the filter, it is passed to the AuthenticationProvider. AuthenticationProvider requires user information and the authentication implementation of UserDetailsService.
- UserDetailsService is inherited by UserDetail, which encapsulates User user information. At this stage, user information is encapsulated into AuthenticationProvider.
- Next, the AuthenticationProvider that encapsulates the user information will be passed to the ProviderManager in the AuthenticationManager.
ProviderManager will review the AuthenticationProvider again and finally return the filter.
Through Spring Security's authentication implementation, you can see that although the code is concise and clear, it is extremely scalable. Spring Security supports multiple authentication and authorization mechanisms, including username and password authentication, JWT token authentication, OAuth2 authentication, etc. At the same time, Spring Security also provides a variety of default configurations that can be adjusted and expanded as needed.