spring security的密码认证逻辑
第一步:在我们自定义的LoginService里,使用@Resource注入一个AuthenticationManager
@Resource private AuthenticationManager authenticationManager;
注入AuthenticationManager以后,就可以在LoginService的登录方法里,通过调用authenticationManager.authenticate方法,触发整个认证逻辑:
authentication = authenticationManager .authenticate(new UsernamePasswordAuthenticationToken(username, password));
密码认证的起源是WebSecurityConfigurerAdapter.java在authenticate方法里,将认证过程委托给AuthenticationManager,由AuthenticationManager发起。
if (this.delegate != null) { return this.delegate.authenticate(authentication); } else { synchronized(this.delegateMonitor) { if (this.delegate == null) { this.delegate = (AuthenticationManager)this.delegateBuilder.getObject(); this.delegateBuilder = null; } } return this.delegate.authenticate(authentication); }
委托最终到了AbstractUserDetailsAuthenticationProvider.java,在authenticate方法里,会先从userCache里获取UserDetails,如果userCache里拿到的是null,就进行retrieveUser,也就是根据账号、密码到数据库里去取用户信息,以下仅为摘要,详细内容可参考org/springframework/security/authentication/dao/AbstractUserDetailsAuthenticationProvider.java
一、从userCache取
UserDetails user = this.userCache.getUserFromCache(username);
二、userCache拿到null,就retrieveUser,从数据库取
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
三、retrieveUser取的过程,如果发生异常,会抛出异常,如果顺利取到了用户信息,会进行preAuthenticationChecks和additionalAuthenticationChecks,preAuthenticationChecks通俗的理解就是:预检查,预检查的内容包括:账号是否被锁定,是否有效等等
user = retrieveUser(username,
(UsernamePasswordAuthenticationToken) authentication);
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user,
(UsernamePasswordAuthenticationToken) authentication);
四、preAuthenticationChecks通过以后,会进行postAuthenticationChecks,接着把用户信息写入到缓存,最后createSuccessAuthentication(principalToReturn, authentication, user)
postAuthenticationChecks.check(user);
if (!cacheWasUsed) {
this.userCache.putUserInCache(user);
}
Object principalToReturn = user;
if (forcePrincipalAsString) {
principalToReturn = user.getUsername();
}
return createSuccessAuthentication(principalToReturn, authentication, user);
authenticate结束,会返回一个result的数据结构给到我们,表明认证的结果,如下图
如果这个result不为null,就会执行copyDetails,具体的代码逻辑如下:
if (result != null) { copyDetails(authentication, result); break; }
copyDetails执行完,在最后阶段,会把result数据结构里对应的credentials重置为null,这样做的目的想必都可以理解,credentials就是明文密码,清空credentials是为了安全考量,至此认证过程就告一段落了。