news 2026/6/23 2:52:21

双 Token 机制下的无感刷新(Refresh Token)后端实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双 Token 机制下的无感刷新(Refresh Token)后端实现

AccessToken 过期的三种实践场景

假设AccessToken有效期 30 分钟,RefreshToken有效期 30 天。

场景 1:关闭网页,短时间内(如 5 分钟)又打开

  • 表现直接进入
  • 原理:前端从存储中读取AccessToken发送请求。后端 Filter 发现 Token 签名正确且未过期(只过了 5 分钟),校验通过,用户无需重新登录。

场景 2:关闭网页,过了一天又打开

  • 表现页面闪烁一下(自动刷新),正常进入
  • 原理
  1. 前端发送旧AccessToken,后端返回401 Unauthorized
  2. 前端 Axios 拦截器捕获 401,自动读取RefreshToken调用刷新接口。
  3. 后端验证RefreshToken有效,返回新AccessToken
  4. 前端用新 Token 重新发起业务请求,用户感知不到重新登录的过程。

场景 3:打开网页并持续浏览超过 30 分钟

  • 表现无感续期
  • 原理
  • 在第 31 分钟时,发出的业务请求会因AccessToken过期报 401。
  • 前端拦截器发起“静默刷新”,获取新 Token 并继续完成刚才的操作。
  • 用户在操作过程中几乎无察觉,流程与场景 2 类似。


深度解析:双 Token 机制下的无感刷新(Refresh Token)后端实现

1. 为什么要设计刷新令牌?

在 JWT 架构中,AccessToken通常设置较短的有效期(如 30 分钟),目的是降低泄露后的风险。但如果直接让用户每 30 分钟登录一次,体验会崩溃。
刷新令牌(RefreshToken)的存在,就是为了在不暴露用户账号密码的前提下,实现“令牌续期”,平衡安全与体验。


2. 后端核心实现流程

基于代码逻辑,后端处理refresh_token请求时遵循以下严谨步骤:

第一步:合法性与归属权校验

  • 令牌存在性:首先通过字符串查询数据库/Redis,确认该refreshToken是由系统颁发的。
  • 客户端匹配:校验请求携带的clientId是否与令牌记录中的编号一致。

安全要点:防止攻击者拿着 A 系统的刷新令牌去请求 B 系统的访问令牌(多租户/多应用场景下的关键防御)。

第二步:旧令牌的“彻底清理”(幂等性保证)

  • 双写删除:在生成新令牌前,系统会查出该refreshToken关联的所有旧accessToken
  • 同步清理:同时从MySQLRedis中删除这些旧访问令牌。

目的:确保一个刷新令牌在同一时刻只对应一个有效的访问令牌,防止产生孤儿 Token 占用空间或造成安全隐患。

第三步:过期判定与自毁

  • 逻辑检查:判断refreshTokenexpiresTime是否早于当前时间。
  • 过期处理:一旦发现刷新令牌也过期了,后端会物理删除该刷新令牌,并抛出UNAUTHORIZED异常。

结果:此时前端拦截器会引导用户跳转至登录页,完成“30天”后的重新认证。

第四步:新令牌的“以旧换新”

  • 调用创建方法,生成全新的accessToken,并重新存入缓存,返回给前端。

3. 核心代码

@Override@Transactional(rollbackFor=Exception.class)publicOAuth2AccessTokenDOrefreshAccessToken(StringrefreshToken,StringclientId){// 查询访问令牌OAuth2RefreshTokenDOrefreshTokenDO=oauth2RefreshTokenMapper.selectByRefreshToken(refreshToken);if(refreshTokenDO==null){throwexception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"无效的刷新令牌");}// 校验 Client 匹配OAuth2ClientDOclientDO=oauth2ClientService.validOAuthClientFromCache(clientId);if(ObjectUtil.notEqual(clientId,refreshTokenDO.getClientId())){throwexception0(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"刷新令牌的客户端编号不正确");}// 移除相关的访问令牌List<OAuth2AccessTokenDO>accessTokenDOs=oauth2AccessTokenMapper.selectListByRefreshToken(refreshToken);if(CollUtil.isNotEmpty(accessTokenDOs)){oauth2AccessTokenMapper.deleteByIds(convertSet(accessTokenDOs,OAuth2AccessTokenDO::getId));oauth2AccessTokenRedisDAO.deleteList(convertSet(accessTokenDOs,OAuth2AccessTokenDO::getAccessToken));}// 已过期的情况下,删除刷新令牌if(DateUtils.isExpired(refreshTokenDO.getExpiresTime())){oauth2RefreshTokenMapper.deleteById(refreshTokenDO.getId());throwexception0(GlobalErrorCodeConstants.UNAUTHORIZED.getCode(),"刷新令牌已过期");}// 创建访问令牌returncreateOAuth2AccessToken(refreshTokenDO,clientDO);}

4. 技术亮点分析(面试/博客加分项)

1. 事务管理 (@Transactional)

在刷新过程中涉及“删旧”与“增新”两个数据库操作,必须保证原子性。如果新令牌生成失败,旧令牌的删除动作应该回滚。

2. 缓存与持久化双校验

  • MySQL负责持久化存储,作为“真值来源”。
  • Redis负责高性能校验,供TokenAuthenticationFilter快速读取。
    这种设计既保证了系统在高并发下的响应速度,又保证了数据不丢失。

3. 安全防范:令牌轮转 (Token Rotation)

虽然此处的refreshToken是复用的,但每次刷新都会注销掉之前所有的accessToken。这在一定程度上防止了令牌被截获后的长期滥用。


5. 总结:前端如何配合?

后端逻辑写得再好,也需要前端的**响应拦截器(Response Interceptor)**配合:

  1. 监控到业务接口返回401(AccessToken 过期)。
  2. 进入“静默重试”队列,调用后端的refresh-token接口。
  3. 获取新 Token 后,自动替换本地存储,并原路重发刚才失败的业务请求。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/19 23:53:35

【课程设计/毕业设计】基于springboot+Vue的课程设计选题管理系统设计基于SpringBoot和Vue的毕业设计选题管理系统的设计与实现【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/16 15:45:41

光伏MPPT仿真之变步长扰动观察法探索

光伏MPPT仿真-变步长扰动观察法 定步长&#xff0c;有配套video 在光伏系统中&#xff0c;最大功率点跟踪&#xff08;MPPT&#xff09;技术至关重要&#xff0c;它能让光伏电池始终在最大功率点附近工作&#xff0c;提升发电效率。今天咱就唠唠变步长扰动观察法&#xff0c;这…

作者头像 李华
网站建设 2026/6/16 15:45:39

python语言随机人物头像图片生成器程序代码

import random from PIL import Image, ImageDrawclass RandomAvatarGenerator:def __init__(self, avatar_size200):"""初始化头像生成器&#xff0c;默认生成200x200的头像"""self.size avatar_sizeself.center (avatar_size // 2, avatar_s…

作者头像 李华
网站建设 2026/6/21 5:49:02

基于 Python 的人脸+服装双重验证照片识别系统

从海量照片中精准找出特定人物的照片,结合人脸识别与服装颜色检测的双重验证方案。 背景 在活动、运动会等场景中,摄影师会拍摄大量照片。如何从成百上千张照片中快速找出某个特定人物的照片?单纯依靠人脸识别可能会有误匹配,本文介绍一种结合人脸识别和服装颜色检测的双重…

作者头像 李华
网站建设 2026/6/19 13:40:13

计算机毕业设计springboot牙医诊所管理系统的设计与实现 基于SpringBoot的口腔门诊综合管理平台的设计与实现 SpringBoot驱动的数字化牙科诊所运营系统开发实战

计算机毕业设计springboot牙医诊所管理系统的设计与实现m077bax2 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。当“看牙”从线下排队变成指尖预约&#xff0c;当消毒记录从纸质…

作者头像 李华
网站建设 2026/6/20 19:41:06

有什么好用的降AIGC疑似度工具,知网AI率90%!

2025年起&#xff0c;高校已明确要求毕业论文要检测AIGC率&#xff0c;AI率高于30%或40%就不能参加答辩&#xff0c;而部分学校、硕士论文更加严格&#xff0c;要求在20%以内。 这其中&#xff0c;大多数高校使用的AIGC检测系统是知网、万方、维普等主流查重系统&#xff0c;这…

作者头像 李华