忘记密码找回流程请求拦截器-前端

目录

设置找回密码请求拦截器

1.相关参数

2.约定

代码实现

1. 实现思路

2. 实现代码


校园统一身份认证系统:

基于网络安全,找回密码、重新设置密码的流程和正常登录流程中密钥等请求头不一致。

设置找回密码请求拦截器

1.相关参数

  • clientId  应用ID,在点击忘记密码跳转后携带,如下所示:
http://192.168.31.134:8080/? clientId = webApp &secretKey = 3dtii4jr91iz8ypj &secretValue = ecmo5dro13as5y79
  • secretKey 密钥的key,在点击忘记密码跳转后携带,如下所示:
     
http://192.168.31.134:8080/ ?
clientId = webApp &secretKey = 3dtii4jr91iz8ypj &secretValue = ecmo5dro13as5y79
  • secretValue 密钥的value,在点击忘记密码跳转后携带,如下所示:
http://192.168.31.134:8080/ ?
clientId = webApp &secretKey = 3dtii4jr91iz8ypj &secretValue = ecmo5dro13as5y79
  • nonce 随机字符串,10分钟内不要重复
  • timestamp 时间戳(毫秒),纯数字
  • sign 签名,利用上面的参数,使用SM3加密算法生成的加密字符串,加密前的明文如下所示(加密时没有用到secretKey):
nonce = "{ 随机字符串 }" ×tamp = { 时间戳 ( 毫秒 )} &clientId = "{ 应用 ID}" &secret = "
{secretValue}"
  • jwtSecret 生成jwt的密钥,值是 8w9L95DwBCD9xjkR

2.约定

从统一登录页点击忘记密码跳转时,会携带 1 个参数,如下所示:
http://192.168.31.134:8080/AccountBack ?
key = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGllbnRJZCI6IndlYkFwcCIsInNlY3JldEt
leSI6ImF2dGxuYXlldnBtbWo5NDgiLCJzZWNyZXRWYWx1ZSI6InMzZ2Jma2QzdDI2YWJ5NzQifQ.y1eT
agvFM8gPxC1k2oqZIwr_9-IhyHAhWJqkZ8CFrnI
clientId secretKey secretValue timeEnd 作为参数,以 jwtSecret 为密钥,生成的结果
就是 key ;其中 timeEnd key 有效截止时间的时间戳。
每次请求 前都需要判断 key 是否还有效,如果无效需要重新开始忘记密码的流程。
每次请求 都需要以 clientId timestamp , nonce , secretKey , sign 5 个值为参数,以 jwtSecret
为密钥生成 key ;并将结果放入请求头的 key 参数中。
:
1. 生成 key 时需要的是 secretKey ,而不是 secretValue。

代码实现

1. 实现思路

  1. jwtDecode对key解码。
  2. 获取数据:secretKey密钥,secretValue密钥值,timeEnd有效截至时间,redirectUri退回登录时需要携带url的标识。
  3. 获取当前时间戳检查是否超过有效截至时间。
  4. 生成签名sign、随机字符串nonce(无长度字符限制,为避免出错现在在数字和字母中,符号在解析过程中容易出错),jwt加密重新生成新的key。

2. 实现代码

使用router 文件 index.js 中的 accessToken:
const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});
const VueRouterPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(to) {
  return VueRouterPush.call(this, to).catch((err) => err);
};

router.beforeEach((to, from, next) => {
  const fullPath=to.fullPath.match(/\?(.*)/)
  if(fullPath) {
  const searchParams = new URLSearchParams(fullPath[1])
  if (searchParams.get('key')) {
  localStorage.setItem('accessToken', searchParams.get('key')) 
    next(to.path)
  }
}else {
  next()
}
 
})
export default router;

request1.js(和其他request.js不同)中:

引入文件依赖:

//创建axios实例
import axios from "axios";
// 导入 sm-crypto 库
import sm from "sm-crypto";
import CryptoJS from 'crypto-js'
import { jwtDecode } from "jwt-decode";
import { getToken, setToken, removeToken } from "@/utils/auth";
import { Notification, MessageBox, Message, Loading } from "element-ui";
import errorCode from "@/utils/errorCode";
import { eventBus } from '../../src/main';

请求拦截器:

// 请求拦截器
service.interceptors.request.use(
	(config) => {
		// 在发送请求之前做些什么

		let accessToken = localStorage.getItem("accessToken");
		// console.log("key", accessToken);
		//解码密钥
		const jwtSecret = "8w9L95DwBCD9xjkR"; // 生成JWT密钥,固定数值
		// 解码JWT令牌获取参数
		// clientId secretKey secretValue timeEnd
		const decodedToken = jwtDecode(accessToken, jwtSecret);
		console.log(decodedToken);
		const clientId = decodedToken.clientId; //应用ID
		console.log("clientId");
		console.log(clientId);
		const secretKey = decodedToken.secretKey; //密钥
		const secretValue = decodedToken.secretValue; //密钥值
		const timeEnd = decodedToken.timeEnd; //获取key有效截止时间的时间戳
		const redirectUri = decodedToken.redirectUri ? decodedToken.redirectUri : null;

		window.redirectUri = redirectUri;
		window.clientId = clientId; // 存储在全局变量中
		// 通过事件总线发送事件通知
		eventBus.$emit('dataUpdated', {clientId,redirectUri});
		console.log("window.clientId");
		console.log(window.clientId);

		// 检查key是否有效
		if (timeEnd && Date.now() > Number(timeEnd)) {
			// key已过期,重新开始忘记密码流程
			return Promise.reject(); //超时,请求中断
		}

		const nonce = generateNonce(); // 生成随机字符串nonce
		const timestamp = Date.now(); // 获取当前时间戳(毫秒级别)
		const sign = generateSign(nonce, timestamp, clientId, secretValue); // 生成签名sign
		// 生成加密key
		const payload = {
			clientId,
			timestamp,
			nonce,
			secretKey,
			sign,
		};
		const jwtToken = generateKey(payload, jwtSecret);
		// console.log("key");
		// console.log(jwtToken);
		config.headers["key"] = jwtToken; // 将key添加到请求头中并转换为字符串类型 // 将key添加到请求头中并转换为字符串类型
		return config;
	},
	(error) => {
		// 对请求错误做些什么
		return Promise.reject(error);
	}
);
// 生成随机字符串nonce的函数
function generateNonce() {
	const characters =
		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
	const length = 16;
	let nonce = "";

	for (let i = 0; i < length; i++) {
		nonce += characters.charAt(Math.floor(Math.random() * characters.length));
	}
	return nonce;
}

// 生成签名sign的函数
function generateSign(nonce, timestamp, clientId, secretValue) {
	const plaintext = `nonce=${nonce}&timestamp=${timestamp}&clientId=${clientId}&secret=${secretValue}`;
	const sign = sm.sm3(plaintext); // 使用sm-crypto库中的sm3函数生成签名
	return sign;
}


// 函数用于将对象编码为Base64格式
function encodeBase64(obj) {
	const stringifiedObj = JSON.stringify(obj);
	const wordArray = CryptoJS.enc.Utf8.parse(stringifiedObj);
	return CryptoJS.enc.Base64.stringify(wordArray).replace(/=+$/, "");
}

// 生成JWT的函数
function generateJWT(payload, secret) {
	// 定义JWT的头部
	const header = { alg: "HS256", typ: "JWT" };
	// 编码头部和负载
	const encodedHeader = encodeBase64(header);
	const encodedPayload = encodeBase64(payload);

	// 生成签名
	const signature = CryptoJS.HmacSHA256(
		encodedHeader + "." + encodedPayload,
		secret
	);
	const signatureBase64 = CryptoJS.enc.Base64.stringify(signature).replace(
		/=+$/,
		""
	);
	const jwtToken = `${encodedHeader}.${encodedPayload}.${signatureBase64}`;
	return jwtToken;
}
// 生成key的函数
function generateKey(payload, jwtSecret) {
	const jwtToken = generateJWT(payload, jwtSecret);
	return jwtToken;
}

响应拦截器(无特殊处理):

function logOutWay() {
	MessageBox.confirm('未登录或登录已过期,请重新登录。', '系统提示', {
		confirmButtonText: '重新登录',
		showCancelButton: false,
		distinguishCancelAndClose: false,
		showClose: false,
		closeOnClickModal: false,
		type: 'warning'
	}
	).then(() => {
		// 跳转到登录页面
		let accessTokenKey = getToken()
    removeToken()
    localStorage.removeItem('accessToken')
    window.location.href = process.env.VUE_APP_BASE_JUMP+'auth/logout?accessToken=' + accessTokenKey + '&redirectUri='+process.env.VUE_APP_BASE_JUMP

	}).catch(() => {

	});
	
}

// 响应拦截器
service.interceptors.response.use(
	(res) => {
		const isEncrypt = true;
		if (isEncrypt === "true" && !matchs(res.config.url, excludPtahs)) {
			//console.log("================解密===================")
			res.data = JSON.parse(interfaceDecryptSm2(res.data));
		}
		// console.log("拦截器===", res);

		// 未设置状态码则默认成功状态
		const code = res.data.code || 0;
		// 获取错误信息
		const msg = errorCode[code] || res.data.msg || errorCode["default"];
		// 二进制数据则直接返回
		if (
			res.request.responseType === "blob" ||
			res.request.responseType === "arraybuffer"
		) {
			// console.log("1111===");
			return res.data;
		}
		if (code === 401) {
		} else if (code === 1) {
			if (msg && msg.includes("key不存在或已过期")) {
				logOutWay()
				// 中断请求
				return Promise.reject("无效的会话,或者会话已过期,请重新登录。");
			} else {
				Message({ message: msg, type: "error" });
				return Promise.reject(new Error(msg));
			}
		} else if (code === 601) {
			Message({ message: msg, type: "warning" });
			return Promise.reject("error");
		}
		// else if (code !== 0) {
		// 	Notification.error({ title: msg })
		// 	return Promise.reject('error')
		// }
		else {
			// console.log("22222===",res.data);
			return res.data;
		}
	},
	(error) => {
		console.log("err====" + error);
		let { message } = error;
		if (message == "Network Error") {
			message = "后端接口连接异常";
		} else if (message.includes("timeout")) {
			message = "系统接口请求超时";
		} else if (message.includes("Request failed with status code")) {
			if (message.substr(message.length - 3) == 401) {
				console.log("401走重新请求token逻辑");
				message = "未登录或登录已过期,请重新登录。";
			} else {
				message = "系统接口" + message.substr(message.length - 3) + "异常";
			}
		}
		Message({ message: message, type: "error", duration: 5 * 1000 });
		return Promise.reject(error);
	}
);

//导入文件
export default service;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

明日周刊-第3期

第3期&#xff0c;分享自己最近的感悟和实用工具。 文章目录 1. 一周热点2. 资源分享3. 言论4. 歌曲推荐 1. 一周热点 国内生产总值持续增长&#xff1a;统计局最新数据显示&#xff0c;2023年全年国内生产总值&#xff08;GDP&#xff09;超过126万亿元&#xff0c;比上年增长…

提升质量透明度,动力电池企业的数据驱动生产实践 | 数据要素 × 工业制造

系列导读 如《“数据要素”三年行动计划&#xff08;2024—2026年&#xff09;》指出&#xff0c;工业制造是“数据要素”的关键领域之一。如何发挥海量数据资源、丰富应用场景等多重优势&#xff0c;以数据流引领技术流、资金流、人才流、物资流&#xff0c;对于制造企业而言…

4 Spring IOC/DI配置管理第三方bean

文章目录 1&#xff0c;IOC/DI配置管理第三方bean1.1 案例:数据源对象管理1.1.1 环境准备1.1.2 思路分析1.1.3 实现Druid管理步骤1:导入druid的依赖步骤2:配置第三方bean步骤3:从IOC容器中获取对应的bean对象步骤4:运行程序 1.1.4 实现C3P0管理步骤1:导入C3P0的依赖步骤2:配置第…

DBO优化GRNN回归预测(matlab代码)

DBO-GRNN回归预测matlab代码 蜣螂优化算法(Dung Beetle Optimizer, DBO)是一种新型的群智能优化算法&#xff0c;在2022年底提出&#xff0c;主要是受蜣螂的的滚球、跳舞、觅食、偷窃和繁殖行为的启发。 数据为Excel股票预测数据。 数据集划分为训练集、验证集、测试集,比例…

博途建立S7-1200PLC与HMS AB7013Profinet通讯

1、新建一个博图项目1200PLC .CPU 1214C ACDC/RIY 6ES7 214-1BG31-0x80 2、安装GSD文件 Install general station description fle (GsD) GSDMLV2.3-HMS-ABC PROFINET GSD 3、连接PLC 4、在线访问 5、增加访问子网络 </

FPGA 以太网传输ov5640视频

1 实验任务 使用 DFZU4EV MPSoC 开发板及双目 OV5640 摄像头其中一个摄像头实现图像采集&#xff0c;并通过开发板上的以太网接口发送给上位机实时显示。 2 系统框架 时钟模块用于为 I2C 驱动模块、以太网顶层模块和开始传输控制模块提供驱动时钟&#xff1b;I2C 驱动模块…

用最小堆实现通用的高效定时器组件

用最小堆实现通用的高效定时器组件 文章目录 用最小堆实现通用的高效定时器组件开篇解决方案类图源码实现测试总结 开篇 在程序开发过程中&#xff0c;定时器会经常被使用到。而在Linux应用开发中&#xff0c;系统定时器资源有限&#xff0c;进程可创建的定时器数量会受到系统限…

Priority Queue实现栈和队列

在排序算法中&#xff0c;堆排序利用了完全二叉树形式的堆结构&#xff0c;结合了插入排序与合并排序的优点&#xff0c;能够以 O ( n log ⁡ n ) O(n\log{n}) O(nlogn)的时间完成排序。优先级队列是可基于堆结构进行实现的一种数据结构&#xff0c;在计算机系统中可以用来记录…

【现代C++】可变参数模板

现代C中的可变参数模板是C11引入的一个功能&#xff0c;允许模板接受可变数量的参数&#xff0c;使得模板编程更加灵活和强大。 1. 基本用法 可变参数模板允许您创建接受任意数量参数的函数或类模板。 template<typename... Args> void func(Args... args) {// 处理参…

C++ 基本运算

何谓运算符和操作数 基本运算 1、双目运算 2、单目运算 3、赋值表达式 表达形式&#xff1a; <变量><表达式>; 表达式是指各种运算符把常量、变量&#xff0c;函数等运算对象连接起来的具有实际意义并符合C语法规则的式子。赋值是指表达式的值赋给一个变量。 …

基于SSM的NEUQ宿舍管理系统的设计与实现

基于SSM的NEUQ宿舍管理系统的设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全 获取源码——》公主号&#xff1a;计算机专业毕设大全

LabVIEW电动汽车直流充电桩监控系统

LabVIEW电动汽车直流充电桩监控系统 随着电动汽车的普及&#xff0c;充电桩的安全运行成为重要议题。通过集成传感器监测、单片机技术与LabVIEW开发平台&#xff0c;设计了一套电动汽车直流充电桩监控系统&#xff0c;能实时监测充电桩的温度、电压和电流&#xff0c;并进行数…

PMP适合哪些人?考试PMP有什么职业要求吗?

威班PMP 3A路过拿证学员 。PMP认证没听说过有啥职业的要求&#xff0c;也没听说过限制在哪些行业可用&#xff0c;根据我考后经验所了解&#xff0c;它并不只作用在某一个领域&#xff0c;知识点也是项目管理相关的工作都能用到&#xff0c;毕竟这些都是通用的专业实践。如果非…

linux命令学习——sort

sort可以对文本文件进行“排序”&#xff0c;比如-n可以对文本&#xff0c;按照首行字母数字顺序排序 -r参数可以对排序结果进行反转 -u参数可以对查看结果去重

3.18_C++_day6_作业

作业要求&#xff1a; 程序代码&#xff1a; #include <iostream>using namespace std;class Animal { private:string name;string color;int *age; public://无参构造函数Animal(){cout << "Animal::无参构造函数" << endl;}//有参构造函数Anim…

基于深度学习的生活垃圾智能分类系统(微信小程序+YOLOv5+训练数据集+开题报告+中期检查+论文)

摘要 本文基于Python技术&#xff0c;搭建了YOLOv5s深度学习模型&#xff0c;并基于该模型研发了微信小程序的垃圾分类应用系统。本项目的主要工作如下&#xff1a; &#xff08;1&#xff09;调研了移动端垃圾分类应用软件动态&#xff0c;并分析其优劣势&#xff1b;…

附近最小 单调队列 滑动窗口 蓝桥杯

q[t]i 的执行过程如下&#xff1a; 首先&#xff0c;t 的值会先自增 1。然后&#xff0c;新值 i 被赋给 q[t]&#xff0c;即元素 i 被插入到数组 q 的下标为 t 的位置上。 q[t]i 的执行过程如下&#xff1a; 首先&#xff0c;i 的值被赋给 q[t]&#xff0c;即元素 i 被插入到数…

深度学习pytorch——可视化visdom(持续更新)

安装可看&#xff1a;e: Error while finding module specification for ‘visdom.server‘ (ModuleNotFoundError: No module name-CSDN博客 在命令行窗口使用python -m visdom.server&#xff0c;会出现一个web地址&#xff0c;在浏览器中访问&#xff0c;即可看见在python中…

2024年noc指导教师认证测评参考试题题目3-4合集

[noc指导教师认证] 测评参考试题 说明:NOC教师指导认证考试题目是从题库里抽题,因此每位老师每次考试题目都不一样以下题目为测试考试时收集到的一些题目,作为辅助提供给各位老师,老师们可以记住题目及答案的具体内容 (选项顺序会变),以免考试时遇到。2024年的做的题目有的…

C++基础9:继承与派生

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C从入门到深入的专栏&#xff0c;参考书籍&#xff1a;《深入浅出 C {\rm C} C》(马晓锐)和《从 C {\rm C} C到 C {\rm C} C精通面向对象编程》(曾凡锋等)。 8.继承与派生 8.1 继承与派生基础 继承与派生举例理解&#…