1. 结论
// 调用链
AuthenticationManager.authenticate()  --> ProviderManager.authenticate() --> DaoAuthenticationProvider(AbstractUserDetailsAuthenticationProvider).authenticate()
// 处理
在最后的 authenticate() 方法中,调用了 UserDetailsService.loadUserByUsername() 并进行了密码校验,校验成功就构造一个认证过的 UsernamePasswordAuthenticationToken 对象放入 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.classfor (AuthenticationProvider provider : getProviders()) {// toTest == UsernamePasswordAuthenticationToken.class// 其实就是判断 toTest 是不是UsernamePasswordAuthenticationToken类,成立if (!provider.supports(toTest)) {continue;}try {=========================================================================================// 最终 DaoAuthenticationProvider.authenticate()result = provider.authenticate(authentication);
=========================================================================================
}
4. DaoAuthenticationProvider.authenticate()

DaoAuthenticationProvider 的父类是 AbstractUserDetailsAuthenticationProvider,实际上调用的是父类的 authentication(),因为继承关系,所以有时候不好判断到底是父类的方法还是子类重写后的方法,建议 debug,非常清楚。

这里主要有三个步骤:

  1. 子类的 retrieveUser(),里面调用了 UserDetailsService.loadUserByUsername() 进行身份查找
  2. 子类的 additionalAuthenticationChecks(),里面调用 passwordEncoder.matches() 进行密码匹配
  3. 子类的 createSuccessAuthentication(),认证完成,往 SecurityContext中放一个认证过的 auth 对象
public abstract class AbstractUserDetailsAuthenticationProvider implementsAuthenticationProvider, InitializingBean, MessageSourceAware {// authenticationpublic Authentication authenticate(Authentication authentication)throws AuthenticationException {// ....
========================================================================================try {// 1. 这个 retrieveUser ,就是判断用户身份,查询内存或者数据库拿到用户对象user = retrieveUser(username,(UsernamePasswordAuthenticationToken) authentication);}// 2. 密码校验additionalAuthenticationChecks(user,(UsernamePasswordAuthenticationToken) authentication);Object principalToReturn = user;// 3. 返回一个认证过的对象,注意这里 principle 传的是保存了用户信息的 user 对象,不是 Stringreturn createSuccessAuthentication(principalToReturn, authentication, user);}
5. DaoAuthenticationProvider
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {// 1. retrieveUser(),用户身份判断protected final UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication) {try {=========================================================================================// 就是在这里调用了 UserDetailsService  UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
=========================================================================================}
// 2. additionalAuthenticationChecks() 密码校验
protected void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication)throws AuthenticationException {if (authentication.getCredentials() == null) {logger.debug("Authentication failed: no credentials provided");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials"));}String presentedPassword = authentication.getCredentials().toString();if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {logger.debug("Authentication failed: password does not match stored value");throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials","Bad credentials"));}}// 3. 创建一个已认证的对象protected Authentication createSuccessAuthentication(Object principal,Authentication authentication, UserDetails user) {boolean upgradeEncoding = this.userDetailsPasswordService != null&& this.passwordEncoder.upgradeEncoding(user.getPassword());// 这里又回到 父类了,无语return super.createSuccessAuthentication(principal, authentication, user);}// 直接粘贴在这里 super.createSuccessAuthentication()protected Authentication createSuccessAuthentication(Object principal,Authentication authentication, UserDetails user) {// 调用 UsernamePasswordAuthenticationToken 类 三个构造参数的构造器(认证过的对象创建)UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(),authoritiesMapper.mapAuthorities(user.getAuthorities()));result.setDetails(authentication.getDetails());return result;}
6. UsernamePasswordUnthenticationToken构造器

为什么说选择三个参数的构造器构造的就是一个已认证的对象。我们来看看

/*** 两个参数,构造待认证对象* principle 传 username* credentials 传 passord*/
public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {super(null);this.principal = principal;this.credentials = credentials;// 设置标识,未认证setAuthenticated(false);
}/*** This constructor should only be used 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 传 保存了用户信息的对象(实现了UserDetails接口的对象)* credentials 传 passord,也可以传null,因为认证过后,我们不需要知道密码,也是一种保护* authorities 传 用户的权限列表*/
public UsernamePasswordAuthenticationToken(Object principal, Object credentials,Collection<? extends GrantedAuthority> authorities) {super(authorities);this.principal = principal;this.credentials = credentials;// 标记已认证 super.setAuthenticated(true);
}

从这里也可以看出为什么 pinciplecredentials 的类型都是 Object,因为 pinciple 认证前需要传 String 类型的 username,认证后需要传实现了UserDetails 接口的用户对象;而 credentials 认证前需要传前端传来的String类型的password,认证后需要传 String类型的密码 或者 null

通常都是,接收 前端传来的 usernamepassword,调用 两个参数的构造器,创建一个未认证的对象,交给AuthenticationManager进行认证。认证成功后,调用三个参数的构造器,创建一个已认证的对象。

AuthenticationManager 的 authentication 过程相关推荐

  1. 基于SAML2.0的SAP云产品Identity Authentication过程介绍

    SAP官网的架构图 https://cloudplatform.sap.com/scenarios/usecases/authentication.html 上图介绍了用户访问SAP云平台时经历的Au ...

  2. AuthenticationManager验证原理分析

    本文来说下AuthenticationManager验证原理 文章目录 AuthenticationManager概述 AuthenticationManager相关类图 security认证流程 A ...

  3. ASP.NET Core Identity 实战(4)授权过程

    这篇文章我们将一起来学习 Asp.Net Core 中的(注:这样描述不准确,稍后你会明白)授权过程 前情提要 在之前的文章里,我们有提到认证和授权是两个分开的过程,而且认证过程不属于Identity ...

  4. Spring Security认证过程

    2019独角兽企业重金招聘Python工程师标准>>> Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一 ...

  5. 一张大图了解ASP.NET Core 3.1 中的Authentication与Authorization

    下面是一张ASP.NET Core 3.1 中关于Authentication与Authorization的主流程框线图,点击这里查看全图:https://johnnyqian.net/images/ ...

  6. Authentication和Authrization(上)

    两个案例 第一个案例是几个月前,我收到一位朋友的邮件,邀请我加入一个叫ShoppyBag的网站.我去看了,没想到注册后就让我登录GMail帐号,并且GMail提示我该网站需要访问我的通讯录,于是我当即 ...

  7. Spring Security:身份验证令牌Authentication介绍与Debug分析

    在Spring Security中,通过Authentication来封装用户的验证请求信息,Authentication可以是需要验证和已验证的用户请求信息封装.接下来,博主介绍Authentica ...

  8. print在python2和python3的区别_Python2和Python3中print的不同点

    在Python2和Python3中都提供print()方法来打印信息,但两个版本间的print稍微有差异 主要体现在以下几个方面: 1.python3中print是一个内置函数,有多个参数,而pyth ...

  9. Spring security (一)架构框架-Component、Service、Filter分析

      想要深入spring security的authentication (身份验证)和access-control(访问权限控制)工作流程,必须清楚spring security的主要技术点包括关键 ...

最新文章

  1. randaugment
  2. 无法访问gcr.io的几种解决办法
  3. linux 高级命令
  4. 【Python CheckiO 题解】Multiply (Intro)
  5. adb push命令传文件到手机_Android调试桥(adb)
  6. 嵌入式工作笔记0005---嵌入式发展和组成
  7. NetApp公司的4KB块写入技术真能容纳更多数据吗?
  8. 如何在C#中生成与PHP一样的MD5 Hash Code
  9. 盈建科中地震波_SIMQKE_GR、SeismoSignal、中国建筑抗震设计规范反应谱v1.0----时程分析地震波生成及分析必备软件...
  10. STK X教程—C++/CLI
  11. YDOOK:ANSYS 谐波分析的要点和主要应用场景 谐波效应的来源
  12. ACM题库(计蒜客A1001整除问题)
  13. win2008服务器系统玩红警,win10系统玩红警卡死的两种方法
  14. 【Java】算法之矩阵的加减乘除运算
  15. 类加载——类加载时机、类加载过程、类加载器
  16. 北大AI公开课第十一课--语言智能的进展by微软亚洲研究院周明
  17. 再议IIC协议与设计【3】 --SCCB总线介绍
  18. 犀牛插件-获取曲面表面点-Python-坐标点数组-rhino插件
  19. 源码分享意义何在?为何很多官方软件开发商都会有破解版和bug版本的系统盛行?
  20. 电脑关机状态重置BIOS

热门文章

  1. 【Stacking改进】基于随机采样与精度加权的Stacking算法
  2. 见或不见! see me or not!
  3. matlab 二分法求最优解
  4. ThreadPoolExecutor 线程池和redisson加上手动事务踩的坑
  5. 隔壁老王月月入5W,小王回回考100,这轮回的人生...
  6. 百度云加速下载Proxyee-down的下载与安装教程2.x
  7. 如何用Python复现吉布斯现象?
  8. 抖音uv价值怎么计算?直播间如何提高uv价值?
  9. mysql的while循环语句,MySQL循环语句之while循环测试
  10. 用CSS和JS画出来的美女(酷)