Pig4Cloud之登陆验证(一)客户端认证处理

news2024/11/18 0:00:26

前端登陆

handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.$store
              .dispatch("LoginByUsername", this.loginForm)
              .then(() => {
                this.$router.push({path: this.tagWel.value});
              })
              .catch(() => {
                this.refreshCode();
              });
        }
      });
    }

看一下LoginByUsername,在/src/store/modules/user.js中

const scope = 'server'

export const loginByUsername = (username, password, code, randomStr) => {
  const grant_type = 'password'
  let dataObj = qs.stringify({'username': username, 'password': password})

  let basicAuth = 'Basic ' + window.btoa(website.formLoginClient)

  // 保存当前选中的 basic 认证信息
  setStore({
    name: 'basicAuth',
    content: basicAuth,
    type: 'session'
  })

  return request({
    url: '/auth/oauth2/token',
    headers: {
      isToken: false,
      Authorization: basicAuth
    },
    method: 'post',
    params: {randomStr, code, grant_type, scope},
    data: dataObj
  })
}

客户端认证

当访问 OAuth2 相关接口时(/oauth2/token/oauth2/introspect/oauth2/revoke),授权服务器需要进行客户端认证。
Spring Authorization Server 截至目前支持如下五种客户端认证方式:client_secret_basicclient_secret_postclient_secret_jwtprivate_key_jwtnone (针对公共客户端)

OAuth2ClientAuthenticationFilter

实现客户端认证的拦截器就是 OAuth2ClientAuthenticationFilter。 其核心代码如下:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

	if (!this.requestMatcher.matches(request)) {
		filterChain.doFilter(request, response);
		return;
	}

	try {
		Authentication authenticationRequest = this.authenticationConverter.convert(request);
		if (authenticationRequest instanceof AbstractAuthenticationToken) {
			((AbstractAuthenticationToken) authenticationRequest).setDetails(
					this.authenticationDetailsSource.buildDetails(request));
		}
		if (authenticationRequest != null) {
			Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
			this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
		}
		filterChain.doFilter(request, response);

	} catch (OAuth2AuthenticationException ex) {
		this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
	}
}

其核心逻辑就是通过 authenticationConverter 从 request 中解析出客户端认证信息,构建成 Authentication,再通过 authenticationManager 对 Authentication 进行认证。

DelegatingAuthenticationConverter

authenticationConverter 的类型实际上是 DelegatingAuthenticationConverter,它持有一个 AuthenticationConverter 列表(不同的认证请求,其参数不同,所以会有不同的AuthenticationConverter实现类)。
DelegatingAuthenticationConverter 在解析请求时会遍历 AuthenticationConverter 列表,当某个 AuthenticationConverter 解析成功时,立即返回,这也能确定此请求是什么认证方式,后续再执行对应的认证逻辑。

private AuthenticationConverter authenticationConverter;

public OAuth2ClientAuthenticationFilter(AuthenticationManager authenticationManager,
			RequestMatcher requestMatcher) {
		Assert.notNull(authenticationManager, "authenticationManager cannot be null");
		Assert.notNull(requestMatcher, "requestMatcher cannot be null");
		this.authenticationManager = authenticationManager;
		this.requestMatcher = requestMatcher;
		this.authenticationConverter = new DelegatingAuthenticationConverter(
				Arrays.asList(
						new JwtClientAssertionAuthenticationConverter(),
						new ClientSecretBasicAuthenticationConverter(),
						new ClientSecretPostAuthenticationConverter(),
						new PublicClientAuthenticationConverter()));
	}

ProviderManager

authenticationManager 的类型实际上是 ProviderManager,它持有一个 AuthenticationProvider 列表(不同的认证方式,其认证逻辑不同,所以会有不同的AuthenticationProvider实现类)。

AuthenticationManager 接口的默认实现为 ProviderManager
image

authenticationManager调用authenticate
image

调用 AuthenticationProvider 中的 supports(Class<?> authentication) 方法,判断是否支持当前的 Authentication 请求。

public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		......

		for (AuthenticationProvider provider : getProviders()) {
			if (!provider.supports(toTest)) {
				continue;
			}

只有支持当前 Authentication 请求的 AuthenticationProvider 才会继续后续逻辑处理。
然后调用 AuthenticationProvider 中的 authenticate 方法进行身份认证。
此处的provider为ClientSecretAuthenticationProvider
image

public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		......

		for (AuthenticationProvider provider : getProviders()) {
			if (!provider.supports(toTest)) {
				continue;
			}

			......

			try {
				result = provider.authenticate(authentication);
				......
			}

ClientSecretAuthenticationProvider中调用RegisteredClientRepository,通过clientId去数据库查询client
image
image

如果认证成功且返回的结果不为 null,则执行 authentication details 的拷贝逻辑。

try {
    result = provider.authenticate(authentication);

    if (result != null) {
        copyDetails(authentication, result);
        break;
    }
}

......

private void copyDetails(Authentication source, Authentication dest) {
    if ((dest instanceof AbstractAuthenticationToken) && (dest.getDetails() == null)) {
        AbstractAuthenticationToken token = (AbstractAuthenticationToken) dest;

        token.setDetails(source.getDetails());
    }
}

如果发生 AccountStatusExceptionInternalAuthenticationServiceException 异常,则会通过Spring事件发布器AuthenticationEventPublisher 发布异常事件。

catch (AccountStatusException e) {
    prepareException(e, authentication);
    // SEC-546: Avoid polling additional providers if auth failure is due to
    // invalid account status
    throw e;
}
catch (InternalAuthenticationServiceException e) {
    prepareException(e, authentication);
    throw e;
}

......

private void prepareException(AuthenticationException ex, Authentication auth) {
    eventPublisher.publishAuthenticationFailure(ex, auth);
}

如果异常为其它类型的 AuthenticationException,则将此异常设置为lastException并返回。

catch (AuthenticationException e) {
    lastException = e;
}

如果认证结果为 null,且存在父 AuthenticationManager,则调用父 AuthenticationManager 进行同样的身份认证操作,其处理逻辑基本同上。

if (result == null && parent != null) {
    // Allow the parent to try.
    try {
        result = parentResult = parent.authenticate(authentication);
    }
    catch (ProviderNotFoundException e) {
        // ignore as we will throw below if no other exception occurred prior to
        // calling parent and the parent
        // may throw ProviderNotFound even though a provider in the child already
        // handled the request
    }
    catch (AuthenticationException e) {
        lastException = parentException = e;
    }
}

如果认证结果不为 null,同时,此时的 eraseCredentialsAfterAuthentication 参数为 true,且此时认证后的Authentication 实现了 CredentialsContainer 接口,那么即调用 CredentialsContainer 接口的凭据擦除方法,即eraseCredentials,擦除相关凭据信息。

if (result != null) {
    if (eraseCredentialsAfterAuthentication
        && (result instanceof CredentialsContainer)) {
        // Authentication is complete. Remove credentials and other secret data
        // from authentication
        ((CredentialsContainer) result).eraseCredentials();
    }

    // If the parent AuthenticationManager was attempted and successful than it will publish an AuthenticationSuccessEvent
    // This check prevents a duplicate AuthenticationSuccessEvent if the parent AuthenticationManager already published it
    if (parentResult == null) {
        eventPublisher.publishAuthenticationSuccess(result);
    }
    return result;
}

其中,有一个防止重复发布 AuthenticationSuccessEvent 事件的处理,即 parentResult 为空。如果 parentResult为 null,则代表父 AuthenticationManager 不存在或者没有身份认证成功,也即没有发布过 AuthenticationSuccessEvent 事件。此时,便由此处发布 AuthenticationSuccessEvent 事件。

如果lastException 为 null,则代表当前的 Authentication 并没有对应支持的 Provider。此时,便会抛出相应异常。

if (lastException == null) {
    lastException = new ProviderNotFoundException(messages.getMessage(
        "ProviderManager.providerNotFound",
        new Object[] { toTest.getName() },
        "No AuthenticationProvider found for {0}"));
}

如同防止重复发布 AuthenticationSuccessEvent 事件的处理一样,也有一个防止 AbstractAuthenticationFailureEvent 事件重复发布的逻辑处理。如果 parentException 为 null,则代表父AuthenticationManager 不存在、没有进行身份认证或者发布过 AbstractAuthenticationFailureEvent 事件,此时,便由此处发布 AbstractAuthenticationFailureEvent 事件。

if (parentException == null) {
    prepareException(lastException, authentication);
}

throw lastException;

最后,抛出 lastException。

博客园
腾讯云
掘金
简书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/70431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML制作一个汽车介绍网站【大学生网页制作期末作业】

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Big Faceless:PDF Viewer for JAVA Crack

PDF Viewer是一个可以显示PDF文档的Swing组件。针对不需要完整 API 的客户&#xff0c;Viewer 可以作为 Applet、应用程序或通过 Java Web Start 安装&#xff0c;或嵌入到 Swing 应用程序中。 Big Faceless PDF Library 是一个用于创建、编辑、显示和打印 Acrobat PDF 文档的…

TI Lab_SRR学习_2 天线布局和系统设计

AWR1642具有2个发射天线和4个接收天线。天线布局如下图所示。两根发射天线Tx1和Tx2间距为2lamda,接收天线之间的间距为lamda/2。 下面以TI SRR这个案例为例,讲解根据上述的天线布局如何进行设计。 SRR既要看得远又要分辨率高,设计上采用了多模式雷达的设计思想,具有两种工…

文献阅读(194)Multi-packet Bypassing

文章目录题目&#xff1a;Stay in your Lane: A NoC with Low-overhead Multi-packet Bypassing时间&#xff1a;2022会议&#xff1a;HPCA研究机构&#xff1a;乔治华盛顿大学、GIT 本篇论文的主要贡献&#xff1a; 新的流控制算法FastFlow&#xff0c;用于在非重叠路径上无…

UNIAPP实战项目笔记49 支付成功页面的布局

UNIAPP实战项目笔记49 支付成功页面的布局 实际案例图片 显示确认支付成功页面布局 具体内容图片自己替换哈&#xff0c;随便找了个图片的做示例 具体位置见目录结构 完善布局页面和样式 代码 payment-success.vue部分 <template><view class"payment-success&…

Docker的安装 与 环境配置 及 阿里云镜像仓库配置、常用命令等

目录 一、Docker简介 Docker的应用场景 Docker 的优点 1、简化程序 2、避免选择恐惧症 3、节省开支 Docker的架构 Docker 和虚拟机的区别 下图是虚拟机的体系结构&#xff1a; 下图是Docker的体系结构&#xff1a; 二、Centos7安装Docker 【安装】 安装条件&#x…

实用于单片机的C++字符串切割匹配算法

前几天写GPS模块串口程序的时候遇到了一点小问题&#xff0c;GPS模组上传的数据量大且结构复杂&#xff0c;单片机中又没有上位机中的字符切割函数&#xff0c;琢磨了半天自己写了个切割函数。 本算法中兼具匹配和切割的功能&#xff0c;可以匹配指定的标志并按照指定分隔符将指…

Springboot 使用 Mybatis 启动失败排查定位

收获 当遇到项目启动失败&#xff0c;却没有错误日志打印出来的时候&#xff0c;试试在 run 方法上加个 try-catch&#xff0c;即可捕获到异常 Mybatis 的别名扫描路径不要指定的太宽泛&#xff0c;有可能会出现 Bean 名冲突&#xff0c;导致初始化失败 联想到之前碰到的问题…

无影云电脑——云上安全办公

文章目录无影云桌面介绍安装新手体验特点区别改变无影云桌面 介绍 阿里云无影云桌面&#xff08; Elastic Desktop Service&#xff09;的原产品名为弹性云桌面&#xff0c;融合了无影产品技术后更名升级。它可以为您提供易用、安全、高效的云上桌面服务&#xff0c;帮助您快速…

微信小程序的生命周期概览

IntersectionObserver 用于监听元素是否进入视口&#xff08;与视口是否存在相交&#xff09;&#xff0c;在图片懒加载等场景中被广泛应用&#xff0c;不过除了这个基础的用法&#xff0c;他还有更强大的能力。 使用场景 目前已知的 IntersectionObserver 常用使用场景包括&…

Jenkins-pipeline语法

Pipeline概念 Pipeline是将一个命令/程序/进程的输出发送到另一个命令/程序/进程&#xff0c;进行进一步处理 Pipeline的代码定义了整个构建过程 基本的Pipeline语法格式 声明式的pipeline语法格式 所有的声明都必须包含在pipeline{}中 块只能有节段&#xff0c;指令&#x…

AFT Impulse动态工具,AFT脉冲适用于工作

AFT Impulse动态工具,AFT脉冲适用于工作 AFT脉冲产品是一种强大的动态工具&#xff0c;用于计算低功率管道系统中的压力流量。设计用于液体系统&#xff0c;包括&#xff1a; 水 石油和产品被切割。 化学制品 冷冻剂 科洛尔。。。 AFT脉冲适用于工作&#xff1a; 珊瑚礁的大小和…

jdbc环境配置及操作步骤

文章目录jdbc环境配置jdbc 操作步骤jdbc 环境配置 jdbc开发&#xff0c;需要提前先准备驱动包(下载一个mysql驱动包&#xff09;及配置&#xff08;项目配置引入这个驱动包) 下载链接&#xff1a;mysql驱动包 注意&#xff1a;jar包的版本要和自己本地mysql版本一致 1.创建项…

使用宏基因组的方法快速鉴定新冠病毒SARS-CoV2

使用宏基因组的方法快速鉴定新冠病毒SARS-CoV2 一、如果不考虑成本&#xff0c;可以使用宏基因组测序的方法来快速鉴定新冠病毒SARS-CoV2&#xff0c;这种方法无需扩增、分析简单、准确度高。原理是直接将测序得到的序列数据与分类物种数据库比对&#xff0c;从而得到鉴定结果…

编程参考 - 如何计算字符串的哈希值

字符串的哈希值是什么&#xff1f; 在C&#xff0c;Java等编程语言中&#xff0c;有一种hashmap的数据结构&#xff0c;存储一对key / value&#xff0c;分别是两种对象。 为了加快存取的速度&#xff0c;键值key对象会被转换成一个hash值&#xff0c;一个整数。一般来讲&…

【权限提升】 Windows10 本地提权漏洞复现及详细分析(CVE-2021-1732)

文章目录声明一、漏洞前言二、漏洞描述三、漏洞原理四、漏洞以及EXP分析五、本地复现六、修复补丁声明 本篇文章仅用于技术研究和漏洞复现&#xff0c;切勿将文中涉及操作手法用于非授权下的渗透攻击行为&#xff0c;出现后果与本作者无关&#xff0c;切记&#xff01;&#x…

Excel 中使用线性回归进行预测公司销售季节性与增长

本文将提供有关如何使用线性回归模型在 Microsoft Excel 中执行简单而强大的预测的分步教程。 我们将探索模型的三种变体,并比较特定单变量数据集的结果——产品在 5 年内的月销售额。三个模型变体将是; 原始线性回归 (LR) 模型。具有季节性的 LR 模型——确定特定月份的销售…

架构师知识体系梳理

文章目录1、架构师的职责和能力1.1 架构师的主要能力1.2 架构师的思维模式1.3 架构师具备的架构原则1.4 架构师深知的架构质量属性1.5 程序设计SOLID原则1.6 架构CAP定理1.7 领域驱动设计DDD2 搜索引擎2.1 系统架构2.2 原理篇2.3 常见问题2.4 质量保障3 分布式缓存架构3.1 系统…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java软件缺陷管理系统o255h

现在毕设刚开始。时间还有很多&#xff0c;可以从头开始学也可以。毕设其实不难&#xff0c;难的是我们懒散到这种时候再去静下心学。能自己独立完成尽量自己独立完成。相信你看过很多上面回答的&#xff0c;都不建议去某宝。毕竟这一行参差不齐哈。能找到靠谱的也不容易。近期…

[附源码]Python计算机毕业设计SSM计算机学院科研信息管理系统(程序+LW)

[附源码]Python计算机毕业设计SSM计算机学院科研信息管理系统&#xff08;程序LW) 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。…