JWT 过期后 自动刷新方案
JWT(JSON Web Token)广泛应用于现代 Web 开发中的认证与授权,它以无状态、灵活和高效的特点深受开发者欢迎。然而,JWT 的一个核心问题是 Token 过期后如何处理。本文将总结常见的解决方案,分析其优缺点,并帮助开发者选择适合自己项目的方案。
JWT 过期问题的挑战
- 安全性:如果 Token 长时间有效,泄露后可能导致严重的安全问题;短时间有效则需要频繁刷新。
- 无状态性:JWT 通常是无状态的,如何在不依赖后端存储的情况下管理过期 Token 成为难点。
- 刷新机制:如何设计高效、安全的 Token 刷新机制,避免用户频繁登录体验不佳。
解决方案
方案一:双 Token 模式(Access Token + Refresh Token)
设计思路
- 使用两个 Token:
- Access Token:短生命周期(如 15 分钟)。
- Refresh Token:长生命周期(如 7 天)。
- 客户端使用 Access Token 请求资源;当 Access Token 过期时,使用 Refresh Token 获取新的 Access Token 和 Refresh Token。
优点
- 高安全性:Access Token 即使泄露,时间窗口较短,风险可控。
- 客户端和服务器可以协同管理 Refresh Token,有效防止重复使用攻击。
缺点
- 客户端实现复杂度较高,需要管理两个 Token。
- 需要额外的接口和逻辑处理 Refresh Token。
适用场景
- 对安全性要求较高的系统,如金融、支付平台。
核心代码
后端接口验证 Refresh Token 并生成新 Token:
@PostMapping("/refresh-token")
public ResponseEntity<?> refreshToken(@RequestBody Map<String, String> tokens) {String refreshToken = tokens.get("refreshToken");if (!jwtUtil.checkToken(refreshToken)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid Refresh Token");}Map<String, String> claims = jwtUtil.decode(refreshToken);String newAccessToken = jwtUtil.generateJwtToken(claims.get("username"), claims.get("userId"));String newRefreshToken = jwtUtil.generateRefreshToken(claims.get("username"), claims.get("userId"));return ResponseEntity.ok(Map.of("accessToken", newAccessToken, "refreshToken", newRefreshToken));
}
方案二:固定 Session ID + Token
设计思路
- 后端生成唯一的 Session ID 并与 Token 关联,将会话信息(如 Token 状态、用户信息)存储到 Redis 或数据库。
- 客户端请求时,携带 Session ID 和 Token,后端验证会话状态和 Token。
优点
- 可灵活控制会话状态,支持主动使某些 Session 失效。
- 后端可以精细化管理 Token 状态,无需频繁解析 JWT 签名。
缺点
- 依赖 Redis 或数据库存储会话信息,增加系统复杂度。
- 不完全无状态,分布式部署时需要额外处理会话同步。
适用场景
- 用户登录频繁、对会话状态要求高的系统。
核心代码
// 从 Redis 获取会话信息并验证 Token
SessionInfo sessionInfo = redisUtil.get("session_" + sessionId, SessionInfo.class);
if (sessionInfo == null || !sessionInfo.getToken().equals(token)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Session Invalid");
}// Token 过期时刷新
if (jwtUtil.isTokenExpired(token)) {String newToken = jwtUtil.generateJwtToken(sessionInfo.getUsername(), sessionInfo.getUserId());sessionInfo.setToken(newToken);redisUtil.set("session_" + sessionId, sessionInfo);return ResponseEntity.ok(Map.of("newToken", newToken));
}
方案三:Token 无状态 + 客户端定时刷新
设计思路
- Token 完全无状态,仅存储签名信息和过期时间。
- 客户端定期检查 Token 的有效期,并在即将过期时主动请求刷新。
优点
- 无需后端存储任何会话信息,完全无状态。
- 简单高效,适合分布式系统。
缺点
- 客户端需要管理 Token 刷新逻辑,增加复杂度。
- 无法主动失效某个用户会话(如强制下线)。
适用场景
- 轻量级或低安全需求的系统,如小型工具或内部系统。
核心代码
客户端定时检查并刷新:
function checkTokenExpiry() {const token = localStorage.getItem('accessToken');const payload = JSON.parse(atob(token.split('.')[1]));const expiryTime = payload.exp * 1000;if (Date.now() > expiryTime - 5 * 60 * 1000) { // 提前 5 分钟刷新refreshToken();}
}function refreshToken() {const refreshToken = localStorage.getItem('refreshToken');fetch('/refresh-token', {method: 'POST',body: JSON.stringify({ refreshToken }),headers: { 'Content-Type': 'application/json' }}).then(response => response.json()).then(data => {localStorage.setItem('accessToken', data.accessToken);localStorage.setItem('refreshToken', data.refreshToken);});
}
方案四:Hybrid Token(混合 Token)
设计思路
- 将部分会话信息存储到 Token 中,而状态信息(如是否过期)存储在 Redis。
- Token 验证时仅检查无状态部分,必要时从 Redis 获取状态信息。
优点
- 兼顾无状态性和灵活性。
- 后端可动态管理会话状态,同时减少频繁访问存储。
缺点
- 实现较复杂,适合对性能要求较高的场景。
适用场景
- 高并发、大规模分布式系统,如社交平台、内容分发系统。
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 双 Token 模式 | 高安全性;支持长生命周期管理 | 增加客户端复杂度 | 金融、支付等高安全系统 |
| Session ID + Token | 灵活控制会话状态,支持主动失效 | 依赖 Redis 或数据库存储 | 登录频繁的系统 |
| 无状态 Token | 完全无状态,简单高效 | 客户端复杂度高,无法主动失效 | 内部工具、轻量级系统 |
| Hybrid Token | 兼顾性能和灵活性 | 实现复杂 | 高并发分布式系统 |
结语
不同的方案适用于不同的场景,开发者在选择方案时需要考虑:
- 安全性:是否需要强安全性保障,如支持主动失效。
- 性能:是否需要减少后端存储依赖或高效处理。
- 复杂度:是否愿意增加客户端和后端的实现复杂性。
在实际开发中,可以结合业务需求和技术条件选择最适合的方案,甚至进行多方案组合,实现性能与安全的平衡。
相关文章:
JWT 过期后 自动刷新方案
JWT(JSON Web Token)广泛应用于现代 Web 开发中的认证与授权,它以无状态、灵活和高效的特点深受开发者欢迎。然而,JWT 的一个核心问题是 Token 过期后如何处理。本文将总结常见的解决方案,分析其优缺点,并帮…...
react-amap海量点优化
前言:高版本的react-amap 支持MassMarkers 组件用于一次性添加大量的标记点。本次优化的海量点是在低版本react-amap的基础上。官方推荐使用聚合useCluster属性来优化海量点的渲染。 直接附上代码: import React, { Component } from "react"…...
GRU(门控循环单元)详解
1️⃣ GRU介绍 前面介绍的LSTM可以有效缓解RNN的梯度消失问题,但是其内部结构比较复杂,因此衍生出了更加简化的GRU。GRU把输入门和遗忘门整合成一个更新门,并且合并了细胞状态和隐藏状态。于2014年被提出 2️⃣ 原理介绍 GRU的结构和最简单…...
【代码随想录|回溯算法排列问题】
491.非减子序列 题目链接. - 力扣(LeetCode) 这里和子集问题||很像,但是这里要的是非递减的子序列,要按照给的数组的顺序来进行排序,就是如果我给定的数组是[4,4,3,2,1],如果用子集||的做法先进行排序得到…...
Azure Kubernetes Service (AKS)资源优化策略
针对Azure Kubernetes Service (AKS)的资源优化策略,可以从多个维度进行考虑和实施,以提升集群的性能、效率和资源利用率。以下是一些关键的优化策略: 一、 Pod资源请求和限制 设置Pod请求和限制:在YAML清单中为所有Pod设置CPU和…...
R语言 | 宽数据变成一列,保留对应的行名和列名
对应稀疏矩阵 转为 宽数据框,见 数据格式转换 | 稀疏矩阵3列还原为原始矩阵/数据框,自定义函数 df3toMatrix() 目的:比如查看鸢尾花整体的指标分布,4个指标分开,画到一个图中。每个品种画一个图。 1.数据整理&#…...
RTSP播放器EasyPlayer.js播放器在webview环境下,PC和安卓能够正常播放,IOS环境下播放器会黑屏无法播放
流媒体技术分为顺序流式传输和实时流式传输两种。顺序流式传输允许用户在下载的同时观看,而实时流式传输则允许用户实时观看内容。 流媒体播放器负责解码和呈现内容,常见的播放器包括VLC和HTML5播放器等。流媒体技术的应用场景广泛,包括娱乐…...
.NET周刊【11月第3期 2024-11-17】
国内文章 .NET 9使用Scalar替代Swagger https://www.cnblogs.com/netry/p/18543378/scalar-an-alternative-to-swagger-in-dotnet-9 .NET 9 移除了 Swashbuckle.AspNetCore,因为其维护不力,并转向 Microsoft.AspNetCore.OpenApi。除了 Swashbuckle&am…...
c语言数据22数组使用
1.1数组分配的空间 int a[10]{1,2,3,4,5,6,7,8,9,10};//分配空间 元素类型大小int4*元素个数1040byte 元素之间空间连续 数组名代表数组首元素地址;a 取的是a[0]的地址;&a 是整个数组的地址 说明: 数组首元素地址: 0号元…...
深入理解TensorFlow中的形状处理函数
摘要 在深度学习模型的构建过程中,张量(Tensor)的形状管理是一项至关重要的任务。特别是在使用TensorFlow等框架时,确保张量的形状符合预期是保证模型正确运行的基础。本文将详细介绍几个常用的形状处理函数,包括get_…...
MySQL数据库3——函数与约束
一.函数 1.字符串函数 MySQL中内置了很多字符串函数,常用的几个如下: 使用方法: SELECT 函数名(参数);注意:MySQL中的索引值即下标都是从1开始的。 2.数值函数 常见的数值函数如下: 使用方法: SELECT…...
⾃动化运维利器 Ansible-Jinja2
Ansible-Jinja2 一、Ansible Jinja2模板背景介绍二、 JinJa2 模板2.1 JinJa2 是什么2.2 JinJa2逻辑控制 三、如何使用模板四、实例演示 按顺序食用,口味更佳 ( 1 ) ⾃动化运维利器Ansible-基础 ( 2 ) ⾃动化运维利器 Ansible-Playbook ( 3 ) ⾃动化运维利器 Ansible…...
博客文章怎么设计分类与标签
首发地址(欢迎大家访问):博客文章怎么设计分类与标签 新网站基本上算是迁移完了,迁移之后在写文章的过程中,发现个人的文章分类和标签做的太混乱了,分类做的像标签,标签也不是特别的丰富&#x…...
FastDDS之DataSharing
目录 原理说明限制条件配置Data-Sharing delivery kindData-sharing domain identifiers最大domain identifiers数量共享内存目录 DataReader和DataWriter的history耦合DataAck阻塞复用 本文详细记录Fast DDS中Data Sharing的实现原理和代码分析。 DataSharing的概念࿱…...
计算机网络在线测试-概述
单项选择题 第1题 数据通信中,数据传输速率(比特率,bps)是指每秒钟发送的()。 二进制位数 (我的答案) 符号数 字节数 码元数 第2题 一座大楼内的一个计算机网络系统…...
【MySQL】数据库必考知识点:查询操作全面详解与深度解剖
前言:本节内容讲述基本查询, 基本查询要分为两篇文章进行讲解。 本篇文章主要讲解的是表内删除数据、查询结果进行插入、聚合统计、分组聚合统计。 如果想要学习对应知识的可以观看哦。 ps:本篇内容友友们只要会创建表了就可以看起来了哦!&am…...
鲸鱼机器人和乐高机器人的比较
鲸鱼机器人和乐高机器人各有其独特的优势和特点,家长在选择时可以根据孩子的年龄、兴趣、经济能力等因素进行综合考虑,选择最适合孩子的教育机器人产品。 优势 鲸鱼机器人 1)价格亲民:鲸鱼机器人的产品价格相对乐高更为亲民&…...
游戏引擎学习第15天
视频参考:https://www.bilibili.com/video/BV1mbUBY7E24 关于游戏中文件输入输出(IO)操作的讨论。主要分为两类: 只读资产的加载 这部分主要涉及游戏中用于展示和运行的只读资源,例如音乐、音效、美术资源(如 3D 模型和…...
详解模版类pair
目录 一、pair简介 二、 pair的创建 三、pair的赋值 四、pair的排序 (1)用sort默认排序 (2)用sort中的自定义排序进行排序 五、pair的交换操作 一、pair简介 pair是一个模版类,可以存储两个值的键值对.first以…...
AI驱动的桌面笔记应用Reor
网友 竹林风 说,已经成功的用 mxbai-embed-large 映射到 text-embedding-ada-002,并测试成功了。不愧是爱折腾的人,老苏还没时间试,因为又找到了另一个支持 AI 的桌面版笔记 Reor Reor 简介 什么是 Reor ? Reor 是一款由人工智…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
