实现Token无感刷新

devtools/2025/3/19 6:16:38/

前端开发中,Token 无感刷新是一种常见的优化技术,用于在用户无感知的情况下刷新过期的身份验证 Token,从而避免用户因 Token 过期而需要重新登录。以下是实现 Token 无感刷新的思路和具体实现方法。

实现思路

Token 过期机制:

通常,身份验证 Token 有一个有效期(如 2 小时)。
当 Token 过期后,用户需要重新登录或刷新 Token。

无感刷新的核心:

在 Token 过期前,通过刷新 Token 接口获取新的 Token。
使用新的 Token 替换旧的 Token,并继续用户的请求。

实现步骤:

在请求拦截器中检查 Token 是否即将过期。
如果 Token 即将过期,发起刷新 Token 的请求。
在响应拦截器中处理 Token 过期的情况,重新发起失败的请求。

具体实现

以下是一个基于 Axios 的 Token 无感刷新实现示例:

  1. 安装 Axios
    如果尚未安装 Axios,可以通过以下命令安装:
npm install axios
  1. 封装 Axios 实例
    创建一个封装了 Token 无感刷新逻辑的 Axios 实例。
import axios from "axios";// 创建 Axios 实例
const instance = axios.create({baseURL: "https://api.example.com",timeout: 10000,
});// 存储 Token 和刷新 Token
let token = localStorage.getItem("token") || "";
let refreshToken = localStorage.getItem("refreshToken") || "";// 请求拦截器
instance.interceptors.request.use((config) => {// 如果 Token 存在,添加到请求头if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;},(error) => {return Promise.reject(error);}
);// 响应拦截器
instance.interceptors.response.use((response) => {return response;},async (error) => {const originalRequest = error.config;// 如果 Token 过期且未发起过刷新请求if (error.response.status === 401 && !originalRequest._retry) {originalRequest._retry = true; // 标记为已发起刷新请求try {// 发起刷新 Token 的请求const response = await axios.post("/refresh-token", {refreshToken,});// 更新 Token 和刷新 Tokenconst { token: newToken, refreshToken: newRefreshToken } = response.data;token = newToken;refreshToken = newRefreshToken;localStorage.setItem("token", newToken);localStorage.setItem("refreshToken", newRefreshToken);// 更新请求头中的 TokenoriginalRequest.headers.Authorization = `Bearer ${newToken}`;// 重新发起原始请求return instance(originalRequest);} catch (refreshError) {// 刷新 Token 失败,跳转到登录页localStorage.removeItem("token");localStorage.removeItem("refreshToken");window.location.href = "/login";return Promise.reject(refreshError);}}return Promise.reject(error);}
);export default instance;
  1. 使用封装的 Axios 实例
    在项目中使用封装好的 Axios 实例发起请求。
import axiosInstance from "./axiosInstance";const fetchData = async () => {try {const response = await axiosInstance.get("/data");console.log(response.data);} catch (error) {console.error("请求失败", error);}
};fetchData();

关键点解析

Token 存储:

将 Token 和刷新 Token 存储在 localStorage 或 sessionStorage 中。
每次请求时从存储中读取 Token。

请求拦截器:

在请求拦截器中,将 Token 添加到请求头。

响应拦截器:

在响应拦截器中,检查响应状态码是否为 401(未授权)。
如果 Token 过期,发起刷新 Token 的请求。
刷新成功后,更新 Token 并重新发起原始请求。

刷新 Token 接口:

后端需要提供一个刷新 Token 的接口(如 /refresh-token),接收 refreshToken 并返回新的 token 和 refreshToken。

错误处理:

如果刷新 Token 失败,清除本地存储的 Token 并跳转到登录页。

进一步优化

Token 过期时间检查:

在请求拦截器中检查 Token 的剩余有效期。
如果 Token 即将过期(如剩余 5 分钟),提前刷新 Token。

const isTokenExpired = (token) => {const payload = JSON.parse(atob(token.split(".")[1]));const exp = payload.exp * 1000; // 转换为毫秒return Date.now() >= exp - 5 * 60 * 1000; // 提前 5 分钟刷新
};instance.interceptors.request.use((config) => {if (token && isTokenExpired(token)) {// 发起刷新 Token 的请求refreshToken().then((newToken) => {token = newToken;localStorage.setItem("token", newToken);config.headers.Authorization = `Bearer ${newToken}`;}).catch(() => {localStorage.removeItem("token");window.location.href = "/login";});}return config;},(error) => {return Promise.reject(error);}
);

并发请求处理:

如果多个请求同时发现 Token 过期,确保只发起一次刷新 Token 的请求。
使用一个标志变量(如 isRefreshing)来控制刷新请求的并发。

安全性:

使用 HTTPS 加密传输 Token。
设置合理的 Token 有效期和刷新 Token 的有效期。

总结

通过 Axios 的请求拦截器和响应拦截器,可以实现 Token 的无感刷新,从而提升用户体验。关键在于:
在 Token 过期前主动刷新。
处理并发请求和错误情况。
确保 Token 存储和传输的安全性。
这种方法适用于大多数前后端分离的项目,能够有效减少用户因 Token 过期而需要重新登录的情况。


http://www.ppmy.cn/devtools/168262.html

相关文章

Conda 环境迁移指南

一、环境打包迁移方法对比 方法适用场景所需时间文件大小网络依赖conda-pack离线迁移、复杂依赖、快速部署快(5-15分钟)大(GB级)无YAML导出在线重建、跨平台兼容慢(30分钟)小(KB级)…

【Linux】深度解析Linux进程管理:从进程PCB到创建子进程的全景指南

文章目录 前言一、从任务管理器到内核源码二、进程控制块(task_struct)的体系化设计2.1 先描述2.2 再组织2.3 Linux系统下的PCB设计 三、PID的奥秘:从用户空间到内核空间3.1 PID及相关指令3.2 PPID父进程 四、通过系统调用fork()函数创建子进…

失败的面试经历(ʘ̥∧ʘ̥)

一.面向对象的三大特性 1.封装:将对象内部的属性私有化,外部对象不能够直接访问,但是可以提供一些可以使外部对象操作内部属性的方法。 2.继承:类与类之间会有一些相似之处,但也会有一些异处,使得他们与众…

C#设计模式之工厂模式

C#设计模式之工厂模式 工厂模式包含:简单工厂->工厂方法->抽象工厂,是设计模式中的创建型模式 1. 简单工厂模式:用来生产同一等级结构中的任意产品(对于增加新的产品,需要覆盖已有代码(工厂类里的GetCalcultor…

Linux编辑器

Linux编辑器 yum yum是包管理器,类似于Linux的应用商店,安装和卸载工具需要使用yum,Linux系统中是预装了yum的 rzsz工具: Linux和window的文件互传工具 yum install lrzsz 查看所有的软件列表: yum list el代表centos,base代表软件的提供方是base 卸载软件 yum remove l…

微软OneNote无法同步解决方案

目录 前言原因UWP特性 解决方案C***h注册表 参考链接 前言 假设有多台Windows电脑,最方便且免费的多设备笔记同步方案就是微软自家的OneNote,使用OneDrive自带的5G云存储。 但是在国内大陆的OneNote,经常会出现无法同步、同步失败&#xff1…

基于SpringBoot+Vue的电商应用系统的设计与实现(代码+数据库+LW)

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本电商应用系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息&a…

Java面试黄金宝典1

1. 8 种基本数据类型 整数类型 byte: 它是最小的整数类型,占用 1 个字节(8 位)。在一些对内存使用要求极高的场景,比如嵌入式系统开发、数据传输时对数据量有严格限制的情况,会使用 byte 类型。例如&#x…