写在前面
在前一篇文章中,我们介绍了如何配置spring security的自定义认证页面,以及前后端分离场景下如何获取spring security的CSRF Token。在这一篇文章中我们将来分析一下spring security的认证流程。提示:我使用的spring security的版本是5.3.4.RELEASE。如果读者使用的不是和我同一个版本,源码细微之处有些不同,但是大体流程都是一样的。
认证流程分析
通过查阅spring security的官方文档我们知道,spring security的认证过滤操作由UsernamePasswordAuthenticationFilter 完成。那么,我们这次的流程分析就从这个过滤器开始。
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 = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
private boolean postOnly = true;
public UsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login", "POST"));
}
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// 1. 必须为POST请求
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
//2.取出用户填写的用户名和密码
String username = obtainUsername(request);
String password = obtainPassword(request);
//3.防止出现空指针
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
//4.去掉用户名的空格
username = username.trim();
//5.在层层校验后,开始对username和password进行封装
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
// 6.认证逻辑
return this.getAuthenticationManager()
.authenticate(authRequest);
}
}
从上面的分析我们知道了,当表单信息进入到这个过滤器之后,经过层层校验,将其封装成UsernamePasswordAuthenticationToken对象。接下来我们进入到这个对象里面看看。
以下是部分源码
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 530L;
//用户名
private final Object principal;
//密码
private Object credentials;
//5.1还未认证,走这个构造方法
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
super((Collection)null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
}
AuthenticationManager
在上方第6步,进入了认证逻辑,(真正认证操作在AuthenticationManager里面 )我们接下来进入到AuthenticationManager对象的authentic