SpringSecurity是如何验证用户的?
- 首先调用login接口,传入登录用户名和密码;
- LoginController:
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(用户名, 密码);
Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
- 上述第二句调用WebSecurityConfigurerAdapter的authenticate方法,执行到return this.delegate.authenticate(authentication),this.delegate即AuthenticationManager接口,ProviderManager实现了该接口(authenticate);
- 跳转到ProviderManager继续执行,result = provider.authenticate(authentication)调用AbstractUserDetailsAuthenticationProvider的authenticate方法;
- AbstractUserDetailsAuthenticationProvider的authenticate执行user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
- 进入到DaoAuthenticationProvider的retrieveUser方法,执行UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
- 此时会调用我们自定义的UserDetailsService中的loadUserByUsername方法从数据库获取用户信息,并写入UserDetails中;
实际的密码校验逻辑是在类DaoAuthenticationProvider的additionalAuthenticationChecks中
@Override
@SuppressWarnings("deprecation")
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"));
}
}
处理登录异常是在这里跳转(类ExceptionTranslationFilter):
private void handleSpringSecurityException(HttpServletRequest request, HttpServletResponse response, FilterChain chain, RuntimeException exception) throws IOException, ServletException {
if (exception instanceof AuthenticationException) {
handleAuthenticationException(request, response, chain, (AuthenticationException) exception);
}else if (exception instanceof AccessDeniedException) {
handleAccessDeniedException(request, response, chain, (AccessDeniedException) exception);
}
}