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

目录

设置找回密码请求拦截器

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 timeEndconst decodedToken = jwtDecode(accessToken, jwtSecret);console.log(decodedToken);const clientId = decodedToken.clientId; //应用IDconsole.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(); // 生成随机字符串nonceconst timestamp = Date.now(); // 获取当前时间戳(毫秒级别)const sign = generateSign(nonce, timestamp, clientId, secretValue); // 生成签名sign// 生成加密keyconst 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;

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

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

相关文章

多线程实现

1.多线程&#xff1a;并发实现 主线程和子线程并行实现。 一个进程中有多个线程&#xff0c;可以同时进行多个任务。进程是系统分配的&#xff0c;线程的执行是由调度器决定的。 注意&#xff1a;线程开启不一定执行&#xff0c;由Cpu调度执行。 线程创建的三种方式&#xff…

HarmonyOS系统开发ArkTS常用组件文本输入及参数

TextInput文本输入组件&#xff0c;用于接收用户输入的文本内容。 1、TextInput组件的参数 TextInput(value?:{placeholder?: string|Resource , text?: string|Resource}) placeholder属性用于设置无输入时的提示文本text用于设置输入框当前的文本内容 Entry Component st…

20240316-2-协同过滤(collaborative filtering)

协同过滤(collaborative filtering) 直观解释 协同过滤是推荐算法中最常用的算法之一&#xff0c;它根据user与item的交互&#xff0c;发现item之间的相关性&#xff0c;或者发现user之间的相关性&#xff0c;进行推荐。比如你有位朋友看电影的爱好跟你类似&#xff0c;然后最…

【Review+预测】测试架构演进的曲折之路

文章目录 前言 一、“原始”阶段 二、“小打小闹”阶段 三、“小米加步枪”阶段 四、“摩托化部队”阶段 五、“骑兵连”阶段 六、“海军陆战队”阶段 七、“社区型组织”阶段 前言 近期公司的测试团队需要重新组织安排&#xff0c;本着谦虚谨慎的态度&#xff0c;我从…

代码随想录算法训练营 DAY 17 | 110.平衡二叉树 257.二叉树的所有路径 404.左叶子之和

110.平衡二叉树 平衡二叉树的定义&#xff1a;任何节点的左右子树高度差绝对值不超过1 空树也是AVL! 确定遍历顺序&#xff1a; 求高度用后序&#xff0c;求深度用前序。&#xff08;取决于需不需要从下往上返回结果&#xff09; 先判断它是不是平衡二叉树 如果是就返回 如…

【CVTE 一面凉经Ⅰ】循环依赖如何解决

目录 一.&#x1f981; 开始前的废话二. &#x1f981; 什么是循环依赖&#xff1f;三. &#x1f981;Spring 容器解决循环依赖的原理是什么?五. &#x1f981; 三级缓存解决循环依赖的原理六. &#x1f981; 由有参构造方法注入属性的循环依赖如何解决&#xff1f;七.&#x…

vue3通过el-cascader实现动态菜单切换页面

如果只有一级菜单只会显示一个按钮 <div style"width: 100%; margin-top: 10px; display: flex; align-items: center; border-bottom: 1px solid #ccc;"><template v-for"(menu, index) in cascaderData" :key"index"><el-casc…

整数和浮点数在内存中存储

整数在内存中的存储 整数的2进制表⽰⽅法有三种&#xff0c;即原码、反码和补码。 对于整形来说&#xff0c;数据存放内存中的其实是补码。 在计算机系统中&#xff0c;数值一律用补码来表示和存储。原因是&#xff0c;使用补码&#xff0c;可以使符号位和数值域统一处理&am…

DUSt3R:简化三维重建

3D 重建是从二维 (2D) 图像创建对象或场景的 3D 虚拟表示的任务&#xff0c;可用于模拟、可视化或本地化等多种目的。 它广泛应用于计算机视觉、机器人和虚拟现实&#xff08;VR&#xff09;等多个领域。 在基本设置中&#xff0c;3D 重建方法输入一对图像 I1 和 I2&#xff0c…

关于Java对接网络验证+实践小例子,简单易懂

一个简单的网络验证小例子&#xff0c;各位大佬勿喷 突发奇想&#xff0c;如果一位A友找你拿一份 Working Fruits&#xff0c;但是你不想这位A友把你辛苦劳作、熬夜加点写出的代码分享他或她的另外一位朋友B友&#xff0c;也许并不是很有价值的一个小作业而已&#xff0c;但是就…

数据结构:详解【栈和队列】的实现

目录 1. 栈1.1 栈的概念及结构1.2 栈的实现1.3 栈的功能1.4 栈的功能的实现1.5 完整代码 2. 队列2.1 队列的概念及结构2.2 队列的实现2.3 队列的功能2.4 队列的功能的实现2.5 完整代码 1. 栈 1.1 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的…

模拟B\S服务器(扩展知识点)

3.2 模拟B\S服务器(扩展知识点) 模拟网站服务器&#xff0c;使用浏览器访问自己编写的服务端程序&#xff0c;查看网页效果。 案例分析 准备页面数据&#xff0c;web文件夹。 复制到我们Module中&#xff0c;比如复制到day08中 我们模拟服务器端&#xff0c;ServerSocket类…

SpringCloud Alibaba实战和源码(8)OpenFeign使用

1、 使用Feign实现远程HTTP调用 1.1、常见HTTP客户端 HttpClient HttpClient 是 Apache Jakarta Common 下的子项目&#xff0c;用来提供高效的、最新的、功能丰富的支持 Http 协 议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统 J…

RN开发搬砖经验之—处理“Duplicate class com.github.barteksc.pdfviewer“

问题信息 Duplicate class com.github.barteksc.pdfviewer.PDFView found in modules jetified-AndroidPdfViewer-3.1.0-beta.3-runtime (com.github.TalbotGooday:AndroidPdfViewer:3.1.0-beta.3) and jetified-android-pdf-viewer-2.8.2-runtime (com.github.barteksc:andro…

为车主提供多路况安全保障!“北欧轮胎安全专家”熊牌轮胎迎来全新升级

德国马牌轮胎旗下明星品牌——Gislaved熊牌轮胎迎来全新升级。 自进入中国市场以来&#xff0c;熊牌轮胎凭借着坚韧安全、静音降噪等特点&#xff0c;收获无数好评。此次全新升级的熊牌轮胎&#xff0c;在品牌logo中加入了“北欧棕熊”的形象&#xff0c;并且对此前轮胎标签中的…

qt使用Windows经典风格,以使QTreeView或QTreeWidge有节点线或加号

没有使用Windows经典风格的QTreeView或QTreeWidget显示如下&#xff1a; 使用Windows经典风格的QTreeView或QTreeWidget显示如下&#xff1a; 树展开时&#xff1a; 树未展开时&#xff1a; 可以看到&#xff1a; 未使用Windows经典风格时&#xff0c;QTreeView或QTreeWidget…

【MySQL】基本查询(1)

【MySQL】基本查询&#xff08;1&#xff09; 目录 【MySQL】基本查询&#xff08;1&#xff09;表的增删改查Create单行数据 全列插入多行数据 指定列插入插入否则更新替换 RetrieveSELECT 列全列查询指定列查询查询字段为表达式为查询结果指定别名结果去重 WHERE 条件英语不…

第六篇:视频广告格式上传指南(上) - IAB视频广告标准《数字视频和有线电视广告格式指南》

第六篇&#xff1a; 视频广告格式和上传指南&#xff08;上&#xff09; --- 我为什么要翻译介绍美国人工智能科技公司IAB系列技术标准&#xff08;2&#xff09; 流媒体数字视频的广告格式分为线性和非线性两大类。任何一个广告都可以与显示在视频播放器外部的伴随横幅一起提…

【Linux文件系列】重定向

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

CMake学习(下)

1. 嵌套的CMake 如果项目很大&#xff0c;或者项目中有很多的源码目录&#xff0c;在通过CMake管理项目的时候如果只使用一个CMakeLists.txt&#xff0c;那么这个文件相对会比较复杂&#xff0c;有一种化繁为简的方式就是给每个源码目录都添加一个CMakeLists.txt文件&#xff…