AuthenticationManager的authentication过程
1. 结论
// 调⽤链
AuthenticationManager.authenticate()--> ProviderManager.authenticate()-->DaoAuthenticationProvider(AbstractUrDetailsAuthenticationProvider).auth enticate()
// 处理
在最后的authenticate()⽅法中,调⽤了 UrDetailsService.loadUrByUrname()并进⾏了密码校验,校验成功就构造⼀个认证过的 UrnamePasswordA uthenticationToken 对象放⼊ SecurityContext.
2. AuthenticationManager.authenticate()
public interface AuthenticationManager {
私募基金管理办法// 就这⼀个⽅法
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
ProviderManager 是它的是实现类,实际上调⽤的它的 authentication() ⽅法
3. ProviderManager.authentication()
public class ProviderManager implements AuthenticationManager, MessageSourceAware,
InitializingBean {
// authenticate ⽅法
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// getProviders() -> debug发现其实就⼀个 DaoAuthenticationProvider.class
for(AuthenticationProvider provider :getProviders()){
// toTest == UrnamePasswordAuthenticationToken.class
// 其实就是判断 toTest 是不是UrnamePasswordAuthenticationToken类,成⽴
if(!provider.supports(toTest)){
continue;苏秀道中
}
try{
=========================================================================================
// 最终 DaoAuthenticationProvider.authenticate()
result = provider.authenticate(authentication);
=========================================================================================
}
4. DaoAuthenticationProvider.authenticate()
DaoAuthenticationProvider 的⽗类是 AbstractUrDetailsAuthenticationProvider,实际上调⽤的是⽗类的 authentication(),因为继承关系,所以有时候不好判断到底是⽗类的⽅法还是⼦类重写后的⽅法,建议 debug,⾮常清楚。
这⾥主要有三个步骤:
1. ⼦类的 retrieveUr(),⾥⾯调⽤了 UrDetailsService.loadUrByUrname() 进⾏⾝份查找
第54届金马奖2. ⼦类的 additionalAuthenticationChecks(),⾥⾯调⽤ passwordEncoder.matches() 进⾏密码匹配
3. ⼦类的 createSuccessAuthentication(),认证完成,往 SecurityContext中放⼀个认证过的 auth 对象
public abstract class AbstractUrDetailsAuthenticationProvider implements
AuthenticationProvider, InitializingBean, MessageSourceAware {
// authentication
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// ....
======================================================================================== try{
// 1. 这个 retrieveUr ,就是判断⽤户⾝份,查询内存或者数据库拿到⽤户对象
ur =retrieveUr(urname,
(UrnamePasswordAuthenticationToken) authentication);
}
// 2. 密码校验
additionalAuthenticationChecks(ur,
(UrnamePasswordAuthenticationToken) authentication);
Object principalToReturn = ur;
// 3. 返回⼀个认证过的对象,注意这⾥ principle 传的是保存了⽤户信息的 ur 对象,不是 String
return createSuccessAuthentication(principalToReturn, authentication, ur);
}
5. DaoAuthenticationProvider
public class DaoAuthenticationProvider extends AbstractUrDetailsAuthenticationProvider {
// 1. retrieveUr(),⽤户⾝份判断
protected final UrDetails retrieveUr(String urname,
UrnamePasswordAuthenticationToken authentication){
try{
========================================================================================= // 就是在这⾥调⽤了 UrDetailsService
UrDetails loadedUr =UrDetailsService().loadUrByUrname(urname);
========================================================================================= }
// 2. additionalAuthenticationChecks() 密码校验
protected void additionalAuthenticationChecks(UrDetails urDetails,
UrnamePasswordAuthenticationToken authentication)
throws AuthenticationException {
Credentials()== null){
logger.debug("Authentication failed: no credentials provided");
throw new Message(
"AbstractUrDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
String prentedPassword = Credentials().toString();
if(!passwordEncoder.matches(prentedPassword, Password())){
logger.debug("Authentication failed: password does not match stored value");
throw new Message(
"AbstractUrDetailsAuthenticationProvider.badCredentials",
"Bad credentials"));
}
}
// 3. 创建⼀个已认证的对象
protected Authentication createSuccessAuthentication(Object principal,
欧泊Authentication authentication, UrDetails ur){
boolean upgradeEncoding =this.urDetailsPasswordService != null
&&this.passwordEncoder.Password());
// 这⾥⼜回到⽗类了,⽆语
ateSuccessAuthentication(principal, authentication, ur);
}
// 直接粘贴在这⾥ ateSuccessAuthentication()
protected Authentication createSuccessAuthentication(Object principal,
Authentication authentication, UrDetails ur){
// 调⽤ UrnamePasswordAuthenticationToken 类三个构造参数的构造器(认证过的对象创建)
平安的近义词
UrnamePasswordAuthenticationToken result =new UrnamePasswordAuthenticationToken(
principal, Credentials(),
authoritiesMapper.Authorities()));
result.Details());
return result;
}
6. UrnamePasswordUnthenticationToken构造器
为什么说选择三个参数的构造器构造的就是⼀个已认证的对象。我们来看看
/**
* 两个参数,构造待认证对象
ps箭头怎么画
* principle 传 urname太空大战
* credentials 传 passord
*/
public UrnamePasswordAuthenticationToken(Object principal, Object credentials){
super(null);
this.principal = principal;
// 设置标识,未认证
tAuthenticated(fal);
}
/**
* This constructor should only be ud by <code>AuthenticationManager</code> or
* <code>AuthenticationProvider</code> implementations that are satisfied with
* producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* authentication token.
*
* 两个参数,构造待认证对象
* principle 传保存了⽤户信息的对象(实现了UrDetails接⼝的对象)
* credentials 传 passord,也可以传null,因为认证过后,我们不需要知道密码,也是⼀种保护
* authorities 传⽤户的权限列表
*/
public UrnamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<?extends GrantedAuthority> authorities){
super(authorities);
this.principal = principal;
/
/ 标记已认证
super.tAuthenticated(true);
}
客服常用话术从这⾥也可以看出为什么 pinciple 和 credentials 的类型都是 Object,因为 pinciple 认证前需要传 String 类型的 urname,认证后需要传实现了UrDetails 接⼝的⽤户对象;⽽ credentials 认证前需要传前端传来的String类型的password,认证后需要传 String类型的密码或者 null。
通常都是,接收 前端传来的 urname 和 password,调⽤ 两个参数的构造器,创建⼀个未认证的对象,交给AuthenticationManager进⾏认证。认证成功后,调⽤三个参数的构造器,创建⼀个已认证的对象。