当前位置: 首页 > news >正文

前端无感刷新token

在这里插入图片描述
摘要:

Axios 无感知刷新令牌是一种在前端应用中实现自动刷新访问令牌(access token)的技术,确保用户在进行 API 请求时不会因为令牌过期而中断操作

目录概览

    • XMLHttpRequest
    • Axios
    • Fetch API
    • JQ
    • uni.request
    • 注意事项:

  • 访问令牌(Access Token):用于访问受保护资源的凭证,通常有一定的有效期。
  • 刷新令牌(Refresh Token):用于获取新的访问令牌,当访问令牌过期时使用。

实现步骤:

  1. 设置拦截器:在 Axios的请求拦截器中添加逻辑,检查当前时间与令牌的过期时间。如果访问令牌已过期但刷新令牌仍然有效,则调用刷新令牌接口获取新的访问令牌。
  2. 更新令牌存储:一旦获得新的访问令牌,将其存储到 localStorage、Vuex 或其他状态管理工具中,以便后续请求使用新令牌。
  3. 重试原始请求:在成功刷新令牌后,重新发送被拦截的请求,此时使用新的访问令牌。

XMLHttpRequest

// 创建 XMLHttpRequest 实例
const xhr = new XMLHttpRequest();// 登录成功后保存 Token 和 Refresh Token
function onLoginSuccess(response) {localStorage.setItem('accessToken', response.data.accessToken);localStorage.setItem('refreshToken', response.data.refreshToken);
}// 发起请求的函数
function sendRequest(url, method, data) {return new Promise((resolve, reject) => {xhr.open(method, url);xhr.setRequestHeader('Authorization', `Bearer ${localStorage.getItem('accessToken')}`);xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status === 200) {resolve(JSON.parse(xhr.responseText));} else {reject({ status: xhr.status, response: xhr.responseText });}}};if (method === 'POST' && data) {xhr.send(JSON.stringify(data));} else {xhr.send();}});
}// 刷新 Token 的函数
async function refreshToken() {const refreshToken = localStorage.getItem('refreshToken');const response = await fetch('/path/to/refresh', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({ refresh_token: refreshToken }),});const res = await response.json();if (res.success) {localStorage.setItem('accessToken', res.data.newAccessToken);return true; // 表示刷新成功} else {return false; // 表示刷新失败}
}// 拦截响应并处理 Token 刷新
xhr.addEventListener('readystatechange', function() {if (xhr.readyState === 4 && xhr.status === 401) {refreshToken().then(refreshed => {if (refreshed) {xhr.setRequestHeader('Authorization', `Bearer ${localStorage.getItem('accessToken')}`);xhr.send(); // 重新发送请求} else {alert('请重新登录'); // Token 刷新失败,可能需要用户重新登录}});}
});

Axios

import axios from 'axios';// 创建 Axios 实例
const apiClient = axios.create({baseURL: 'https://your-api-url.com',// 其他配置...
});// 响应拦截器
apiClient.interceptors.response.use(response => {return response;
}, error => {const { response } = error;if (response && response.status === 401) {return refreshToken().then(refreshed => {if (refreshed) {// 令牌刷新成功,重试原始请求return apiClient.request(error.config);} else {// 令牌刷新失败,可能需要用户重新登录return Promise.reject(error);}});}return Promise.reject(error);
});// 令牌刷新函数
function refreshToken() {return apiClient.post('/path/to/refresh', {// 刷新令牌所需的参数,例如 refresh_token}).then(response => {if (response.data.success) {// 假设响应数据中包含新的访问令牌const newAccessToken = response.data.newAccessToken;// 更新令牌存储localStorage.setItem('accessToken', newAccessToken);// 更新 Axios 实例的 headers,以便后续请求使用新令牌apiClient.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;return true; // 表示刷新成功} else {return false; // 表示刷新失败}});
}

Fetch API

// 定义一个函数来处理Fetch请求
async function fetchWithToken(url, options = {}) {const token = localStorage.getItem('token');if (token) {options.headers = {...options.headers,'Authorization': `Bearer ${token}`};}try {const response = await fetch(url, options);if (response.status === 401) { // 假设401表示令牌过期const refreshToken = localStorage.getItem('refreshToken');if (!refreshToken) {throw new Error('No refresh token available');}// 调用刷新令牌接口const refreshResponse = await fetch('/api/refresh-token', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({ refreshToken })});if (refreshResponse.ok) {const data = await refreshResponse.json();localStorage.setItem('token', data.newAccessToken);// 重新尝试原始请求options.headers['Authorization'] = `Bearer ${data.newAccessToken}`;return fetch(url, options);} else {throw new Error('Failed to refresh token');}}return response;} catch (error) {console.error('Fetch error:', error);throw error;}
}// 使用示例
fetchWithToken('/api/protected-resource').then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));
  • fetchWithToken函数: 这是一个封装了Fetch API的函数,它首先检查本地存储中的访问令牌是否存在,并在请求头中添加该令牌。如果响应状态码为401(表示令牌过期),则尝试使用刷新令牌获取新的访问令牌,并重新发送原始请求。
  • 刷新令牌逻辑: 在检测到令牌过期时,函数会调用刷新令牌接口,并将新的访问令牌存储到本地存储中。然后,它会重新设置请求头中的授权信息,并重新发送原始请求。
  • 错误处理: 如果在刷新令牌或发送请求的过程中发生错误,函数会抛出相应的错误,并在控制台中记录错误信息。

JQ

// 创建 JQuery 实例
const apiClient = $.ajaxSetup({baseURL: 'https://your-api-url.com',// 其他配置...
});// 响应拦截器
$.ajaxSetup({complete: function(jqXHR, textStatus) {if (textStatus === 'error' && jqXHR.status === 401) {return refreshToken().then(refreshed => {if (refreshed) {// 令牌刷新成功,重试原始请求return apiClient.request(this);} else {// 令牌刷新失败,可能需要用户重新登录alert('请重新登录');}});}}
});// 令牌刷新函数
function refreshToken() {return $.ajax({url: '/path/to/refresh',method: 'POST',data: {refresh_token: localStorage.getItem('refreshToken')},dataType: 'json'}).then(response => {if (response.data.success) {// 假设响应数据中包含新的访问令牌const newAccessToken = response.data.newAccessToken;// 更新令牌存储localStorage.setItem('accessToken', newAccessToken);// 更新 JQuery 实例的 headers,以便后续请求使用新令牌apiClient.defaults.headers.common['Authorization'] = `Bearer ${newAccessToken}`;return true; // 表示刷新成功} else {return false; // 表示刷新失败}});
}

uni.request

// 导入封装的request插件
import http from './interface';
import { getRefreshToken } from '@/common/api/apis.js'; // 刷新token接口let isRefreshing = false; // 是否处于刷新token状态中
let fetchApis = []; // 失效后同时发送请求的容器
let refreshCount = 0; // 限制无感刷新的最大次数function onFetch(newToken) {refreshCount += 1;if (refreshCount === 3) {refreshCount = 0;fetchApis = [];return Promise.reject();}fetchApis.forEach(callback => {callback(newToken);});// 清空缓存接口fetchApis = [];return Promise.resolve();
}// 响应拦截器
http.interceptor.response((response) => {if (response.config.loading) {uni.hideLoading();}// 请求成功但接口返回的错误处理if (response.data.statusCode && +response.data.statusCode !== 200) {if (!response.config.needPromise) {console.log('error', response);uni.showModal({title: '提示',content: response.data.message,showCancel: false,confirmText: '知道了'});// 中断return new Promise(() => {});} else {// reject Promisereturn Promise.reject(response.data);}}return response;
}, (error) => {const token = uni.getStorageSync('token');const refreshToken = uni.getStorageSync('refreshToken');// DESC: 不需要做无感刷新的白名单接口const whiteFetchApi = ['/dealersystem/jwtLogin', '/dealersystem/smsLogin', '/sso2/login', '/dealersystem/isLogin'];switch (error.statusCode) {case 401:case 402:if (token && !whiteFetchApi.includes(error.config.url)) {if (!isRefreshing) {isRefreshing = true;getRefreshToken({ refreshToken }).then(res => {let newToken = res.data;onTokenFetched(newToken).then(res => {}).catch(err => {// 超过循环次数时,回到登录页,这里可以添加你执行退出登录的逻辑uni.showToast({ title: '登录失效,请重新登录', icon: 'error' });setTimeout(() => {uni.reLaunch({ url: '/pages/login/login' });}, 1500);});}).catch(err => {// refreshToken接口报错,证明refreshToken也过期了,那没办法啦重新登录呗uni.showToast({ title: '登录失效,请重新登录', icon: 'error' });setTimeout(() => {uni.reLaunch({ url: '/pages/login/login' });}, 1500);}).finally(() => { isRefreshing = false });}return new Promise((resolve) => { // 此处的promise很关键,就是确保你的接口返回值在此处resolve,以便后续代码执行addFetchApi((newToken) => {error.config.header['Authorization'] = `Bearer ${newToken}`;http.request(error.config).then(response => {resolve(response);});});});}break;default:break;}
});

注意事项:

  • 错误处理:确保在刷新令牌失败时,有适当的错误处理机制,例如提示用户重新登录。
  • 并发请求:处理多个请求同时需要刷新令牌的情况,避免重复刷新。
  • 安全性:确保刷新令牌的安全存储和传输,防止被恶意攻击者获取。

相关文章:

前端无感刷新token

摘要: Axios 无感知刷新令牌是一种在前端应用中实现自动刷新访问令牌(access token)的技术,确保用户在进行 API 请求时不会因为令牌过期而中断操作 目录概览 XMLHttpRequestAxiosFetch APIJQuni.request注意事项: 访问…...

针对股票评论的情感分类器

🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年11月16日13点39分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文链接 点击开启你的论文编程之旅…...

Day18 Nim游戏

你和你的朋友,两个人一起玩 Nim 游戏: 桌子上有一堆石头。 你们轮流进行自己的回合, 你作为先手 。 每一回合,轮到的人拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。 假设你们每一步都是最优解。请编写一个函数&#xff…...

理解反射,学会反射:撬开私有性质(private)的属性与方法

看到这句话的时候证明:此刻你我都在努力 加油陌生人 个人主页:Gu Gu Study专栏:用Java学习数据结构系列喜欢的一句话: 常常会回顾努力的自己,所以要为自己的努力留下足迹喜欢的话可以点个赞谢谢了。作者:小…...

Redis在高性能缓存中的应用

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 Redis在高性能缓存中的应用 Redis在高性能缓存中的应用 Redis在高性能缓存中的应用 引言 Redis 概述 定义与原理 发展历程 Redi…...

菲涅耳全息图

菲涅耳全息图:记录介质在物光波场的菲涅耳衍射区(物体到记录介质表面的距离在菲涅耳衍射区内)。 一、点源全息图的记录和再现 1.1 记录 设物光波和参考光波是从点源O(xo, yo, zo)和点源 R(xr, yr, zr)发出的球面波, 波长为λ1, 全息底片位于z0 的平面上, 与两个点源…...

STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56

STM32 BootLoader 刷新项目 (十) Flash擦除-命令0x56 1. STM32F407 BootLoader 中的 Flash 擦除功能详解 在嵌入式系统中,BootLoader 的设计是非常关键的部分,它负责引导主程序的启动、升级以及安全管理。而在 STM32F407 等 MCU 上实现 BootLoader&…...

POI word转pdf乱码问题处理

1.使用poi 转换word文档成pdf 导入依赖 <dependency><groupId>com.aspose</groupId><artifactId>words</artifactId><version>16.8.0</version></dependency>2.代码实现: SneakyThrowspublic void wordToPdf(String docPath,…...

【GeekBand】C++设计模式笔记11_Builder_构建器

1. “对象创建” 模式 通过 “对象创建” 模式绕开new&#xff0c;来避免对象创建&#xff08;new&#xff09;过程中所导致的紧耦合&#xff08;依赖具体类&#xff09;&#xff0c;从而支持对象创建的稳定。它是接口抽象之后的第一步工作。典型模式 Factory MethodAbstract …...

面试经典 150 题:20、2、228、122

20. 有效的括号 参考代码 #include <stack>class Solution { public:bool isValid(string s) {if(s.size() < 2){ //特判&#xff1a;空字符串和一个字符的情况return false;}bool flag true;stack<char> st; //栈for(int i0; i<s.size(); i){if(s[i] ( |…...

SQL面试题——持续增长问题

持续增长我们也可以称之为连续增长,本质上还是连续类的问题,前面我们已经介绍过 SQL面试题——最大连续登陆问题 SQL面试题——球员连续四次得分 SQL面试题——间隔连续问题 SQL面试题——蚂蚁SQL面试题 连续3天减少碳排放量不低于100的用户 你可以看看之前的文章,了解…...

nginx源码安装配置ssl域名

nginx源码安装 下载 wget http://nginx.org/download/nginx-1.24.0.tar.gz 解压 tar -zxvf nginx-1.24.0.tar.gz 下载openssl apt install openssl 安装nginx cd nginx-1.24.0 sudo apt-get install libpcre3 libpcre3-dev ./configure --prefix=/home/nginx24 --with-http_ss…...

每日一博 - Java的Shallow Copy和Deep Copy

文章目录 概述创建对象的5种方式1. 通过new关键字2. 通过Class类的newInstance()方法3. 通过Constructor类的newInstance方法4. 利用Clone方法5. 反序列化 Clone方法基本类型和引用类型浅拷贝深拷贝如何实现深拷贝1. 让每个引用类型属性内部都重写clone()方法2. 利用序列化 概述…...

.netcore + postgis 保存地图围栏数据

一、数据库字段 字段类型选择(Type) 设置对象类型为&#xff1a;geometry 二、前端传递的Json格式转换 前端传递围栏的各个坐标点数据如下&#xff1a; {"AreaRange": [{"lat": 30.123456,"lng": 120.123456},{"lat": 30.123456…...

【AI图像生成网站Golang】项目介绍

AI图像生成网站 目录 一、项目介绍 二、雪花算法 三、JWT认证与令牌桶算法 四、项目架构 五、图床上传与图像生成API搭建 六、项目测试与调试(等待更新) 简介 本教程将手把手教你如何从零开始构建一个简单的AI图像生成网站。网站主要包含用户注册、图像生成、分类管理等…...

对称加密算法DES的实现

一、实验目的 1、了解对称密码体制基本原理 2、掌握编程语言实现对称加密、解密 二、实验原理 DES 使用一个 56 位的密钥以及附加的 8 位奇偶校验位&#xff0c;产生最大 64 位的分组大小。这是一个迭代的分组密码&#xff0c;使用称为 Feistel 的技术&#xff0c;其中将加密…...

Spring Boot 启动时修改上下文

Spring Boot 启动时修改上下文 为了让项目在启东时&#xff0c;加载到封装的JAR中的国际化文件在封装JAR是增加以下配置类可用于更改启动上下文中的信息依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoco…...

传奇996_19——常用函数

打印 打印到公告 lua版 sendmsg(*actor*, ConstCfg.notice.own, {"Msg":"<font color\#ff0000\>即将更新属性2222&#xff01;&#xff01;&#xff01;</font>","Type":9}) sendmsg(*actor*, 1, {"Msg":"<fon…...

计算机毕业设计Python+Neo4j知识图谱医疗问答系统 大模型 机器学习 深度学习 人工智能 大数据毕业设计 Python爬虫 Python毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

【Python】如何设置VSCode中的Pylint,消除各种没有必要的警告

前言 最近打开VSCode&#xff0c;编辑之前创建的Python项目&#xff0c;突然发现多了一堆报错和警告&#xff0c;如下图所示。 就非常吓人&#xff0c;因为之前这个项目是没有任何报错的&#xff0c;我赶紧试着运行了一下&#xff0c;还好&#xff0c;可以正常运行&#xff0c;…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...

Axure Rp 11 安装、汉化、授权

Axure Rp 11 安装、汉化、授权 1、前言2、汉化2.1、汉化文件下载2.2、windows汉化流程2.3、 macOs汉化流程 3、授权 1、前言 Axure Rp 11官方下载链接&#xff1a;https://www.axure.com/downloadthanks 2、汉化 2.1、汉化文件下载 链接: https://pan.baidu.com/s/18Clf…...

多模态大语言模型arxiv论文略读(112)

Assessing Modality Bias in Video Question Answering Benchmarks with Multimodal Large Language Models ➡️ 论文标题&#xff1a;Assessing Modality Bias in Video Question Answering Benchmarks with Multimodal Large Language Models ➡️ 论文作者&#xff1a;Jea…...