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

Spring Boot 如何实现 JWT 双令牌机制刷新 access_token?

在 Spring Boot 3.x + Spring Security 6 架构中,采用 30 分钟 Access Token 配合 14 天 Refresh Token 的双令牌组合,可使登录频率下降 98% 的同时将潜在盗用风险窗口控制在安全范围内。

原因分析

JWT 本身是无状态的签名凭证,标准 JWT 不支持吊销,这是所有自动续期方案的根本矛盾起点。若仅依赖 spring-security-jwt(已弃用)或简单自签 token,将无法满足 PCI DSS、GDPR 及等保 2.0 对令牌可追溯、可即时废止的要求。单 Token 机制下,为了安全设置较短有效期(如 15-30 分钟),会导致用户在长时间操作如填写复杂表单、在线考试时频繁遇到登录过期问题;而延长到 24 小时又会引发安全团队警告。双 Token 方案通过两种不同生命周期的令牌实现动态认证:Access Token 承担日常 API 请求的认证职责,Refresh Token 专用于 AT 的刷新操作。

解决方案:后端核心实现

第一步,引入 Maven 依赖。在 pom.xml 中添加 jjwt 0.9.1 版本和 spring-boot-starter-security:io.jsonwebtokenjjwt0.9.1。第二步,配置 JWT 属性。在 application.yml 中设置:jwt: secret: your_secret_key, access-token-expiration: 3600(1 小时), refresh-token-expiration: 604800(1 周)。第三步,创建 JWT 工具类 JWTUtils.java,包含 generateAccessToken 和 generateRefreshToken 方法,使用@Value 注入密钥和过期时间配置。第四步,实现刷新接口防御性代码:@PostMapping("/refresh") 接口需进行三重验证——双重来源验证(Cookie 或 RequestBody)、单次使用机制(Redis 存储 used_rt 前缀标记)、关联设备指纹(X-Device-ID 头校验)。

解决方案:前端无感刷新策略

前端在 Axios 拦截器中捕获 401 错误码,触发无感刷新流程。当 Access Token 过期时,后端返回特定错误码提示前端使用 Refresh Token 刷新。成功获取新 Access Token 后,前端更新本地存储(LocalStorage)并继续处理之前的请求。Refresh Token 应安全存储在 HttpOnly Cookie 中,而非 LocalStorage/SessionStorage 明文存储,防止 XSS 一键盗取。某医疗 SaaS 系统实施该方案时,通过监控发现采用 30 分钟 AT+14 天 RT 的组合效果最佳。

注意事项

第一,存储泄露风险:LocalStorage/SessionStorage 明文存 Refresh Token 会导致 XSS 攻击一键盗取,必须使用 HttpOnly Cookie。第二,绑定缺失问题:Refresh Token 未绑定设备指纹(User-Agent+Canvas+WebGL 哈希)、IP 段或 TLS 会话 ID,攻击者可异地复用。第三,状态失控隐患:Refresh Token 未实现 One-Time-Use + Server-Side Invalidation,中间人可重放两次以上。第四,滑动逻辑缺陷:每次 HTTP 响应都无条件刷新 Access Token 会触发令牌风暴,导致数据库写放大 10 倍以上。第五,密钥安全:密钥硬编码在代码里非常不安全,一旦代码泄露攻击者就能伪造任意 Token,应放到配置文件并通过环境变量管理。

参考来源

来源:CSDN 问答 - Spring Boot 中 JWT 令牌如何实现自动续期与安全刷新(2026 年 4 月 15 日发布)

来源:掘金技术社区 - JWT 自动刷新实战:5 分钟搞定 Spring Boot + Vue 的双 Token 方案(2026 年 3 月 16 日)

来源:博客园 - SpringBoot 中基于 JWT 的双 Token 授权和续期方案详解(2024 年 11 月 8 日)

来源:GitHub 技术文章 - 5 步实现 Spring Boot 中的双 Token 授权与续期(2024 年 11 月 3 日)

原文链接:https://www.zjcp.cc/ask/9648.html

http://www.jsqmd.com/news/754206/

相关文章:

  • 从沙漠到深海:聊聊那些让地震剖面‘变清晰’的静校正‘黑科技’(以Marmousi模型为例)
  • C语言完美演绎9-18
  • 基于vibe-annotations数据集的视频氛围识别:从数据构建到模型部署
  • AI编码助手集成SEO审计:技能即文档的Next.js开发实践
  • 扩散模型超参数优化与工程实践指南
  • 智能教育系统SciEducator的多模态架构与PDCA优化实践
  • 仅限.NET 9 Preview 7+可用!C# 13内联数组三大不可逆优化特性(附BenchmarkDotNet压测报告)
  • LLM4Cov:基于大语言模型的硬件验证测试平台生成框架
  • 黑屏,事件ID 1001,解决办法
  • 别再手动计数了!用STM32F103的编码器模式读取旋转编码器,附TIM4完整配置代码
  • 免费AI API聚合服务:开发者如何低成本接入Claude等大模型
  • 离散扩散语言模型的扩展规律与实战优化
  • 语义视频生成技术解析与应用实践
  • 从Lytro到工业复眼:光场相机除了‘先拍后对焦’,在工业检测里还能怎么玩?
  • OpenMMReasoner:多模态大模型训练框架解析与应用
  • 【限时解密】C# 13 Roslyn源码级委托优化开关:/optimize+ /refstructdelegate /noalloc-delegate(.NET SDK 8.0.300+专属)
  • 别再只会用默认AppBar了!Flutter 3.x 自定义顶部导航栏的10个实战技巧
  • 避坑指南:Unity集成SteamVR 2.0时,Interactable组件参数详解与常见交互Bug修复
  • 5分钟快速上手Notepad--:跨平台文本编辑器的完整入门指南
  • 功能安全C++开发必踩的5个编译器陷阱,从GCC 12到Clang 17全版本验证,附可嵌入PLC固件的检测脚本
  • 【LangChain】使用 LangChain 快速实现 RAG
  • 阿里面试官问:Embedding怎么评估?
  • 告别Keil默认丑字体!保姆级配置教程,打造你的专属暗黑主题(附Fixedsys字体配置)
  • 【Java外部函数配置终极指南】:20年专家亲授JNI/FFM/Incubator三大方案选型避坑清单
  • C++27 std::atomic<T>::wait()性能黑洞预警:当std::memory_order_acquire遇上WFE指令,如何避免ARMv9下线程空转耗尽CPU周期?
  • 2026年Python+AI工具链环境搭建指南:从零到可用的完整配置
  • 高效构建3D可视化应用:F3D专业工具完整指南
  • 基于MCP协议构建AI语音控制Spotify播放器的完整指南
  • 免费部署本地AI代码助手:开源模型替代Claude API的完整实践
  • AVRCP 1.6的隐藏技能:手把手教你实现蓝牙音乐封面传输(基于BIP/OBEX)