在前后端分离的系统里,JWT令牌认证几乎成了标准做法。通常我们会发放两个令牌:一个是短时效的访问令牌(access token),用于每次接口请求鉴权;另一个是长时效的刷新令牌(refresh token),专门用来在访问令牌过期后换取新的令牌。可一旦刷新令牌自身也过了期,整个无感刷新链路就会断掉,用户只能重新登录。本文从机制原理、常见处理方案和工程实践三个角度,讲清楚刷新令牌过期时到底该怎么应对。

刷新令牌过期背后的机制与痛点
JWT本身的特性决定了它一经签发便不可撤销,除非借助服务端状态或极短的过期时间。访问令牌一般设置十分钟到半小时,过期后携带它请求接口会直接被拦截。此时前端拿着刷新令牌去认证服务器的刷新接口,换回新的访问令牌和刷新令牌。但如果刷新令牌也到了过期时间,认证接口会返回类似refresh_token_expired的错误,前端若没处理好,就会陷入死循环或白屏。
很多团队在设计时给刷新令牌设了七天或三十天的固定时效,却忽略了用户可能连续多日不登录,或者刷新令牌在某一刻被服务端主动吊销。当刷新令牌绝对过期,服务端无法确认请求者身份,自然不能签发新令牌。这时候如果前端还缓存着旧令牌反复重试,不仅浪费请求,还可能触发安全告警。理解这一机制,才能针对性设计降级策略。
从安全视角看,刷新令牌比访问令牌敏感得多,因为它能不断派生新令牌。所以它通常要存到服务端数据库或Redis里,并绑定设备信息。一旦过期,就意味着这条信任链终止。我们需要在用户体验和安全边界之间做平衡,既不能让令牌永远有效,也不能稍有过期就强制登出。
刷新令牌过期的三种主流处理方案
第一种是滑动过期策略。每次使用刷新令牌成功换取新令牌时,服务端不仅签发新访问令牌,还签发一个全新的刷新令牌,并把旧刷新令牌作废。只要用户在滑动窗口内活跃,刷新令牌就不断延期,只有长期不活跃才真正过期。这种方案对用户最友好,代码上需要在刷新接口里同时写新的令牌记录并删除旧的。
第二种是绝对过期加宽限期。刷新令牌设一个不可延期的绝对过期时间,比如七天,但允许在过期后二十四小时内携带它去调用一个特殊的续期接口,验证近期活动记录后签发新令牌。这相当于给过期令牌一个缓冲带,避免用户刚好在第七天打开应用就登出。实现时要注意续期接口必须校验原令牌的签名和历史行为,防止被冒用。
第三种是令牌家族与吊销机制。服务端把每次签发的刷新令牌归到一个家族编号下,一旦检测到异常(如修改密码、异地登录),就吊销整个家族。当某个刷新令牌过期,家族里其他令牌也同步失效。这种方式安全性最高,适合金融类应用。下面是一段Node.js的刷新逻辑示例,演示如何判断过期并返回对应错误:
const jwt = require('jsonwebtoken');
function handleRefresh(token, secret) {
try {
// 验证签名并解析,若过期会抛 TokenExpiredError
const payload = jwt.verify(token, secret);
return { ok: true, userId: payload.sub };
} catch (err) {
if (err.name === 'TokenExpiredError') {
// 刷新令牌已过期,前端应跳转登录页
return { ok: false, code: 'refresh_token_expired' };
}
// 其他错误如签名无效
return { ok: false, code: 'invalid_token' };
}
}
工程落地时的存储与前端降级实践
刷新令牌不能只存在前端内存里,否则刷新页面就丢失。常见做法是存到HttpOnly Cookie中,由浏览器自动携带,降低被XSS窃取的风险;或者存到移动端的安全存储区。服务端则用Redis记录令牌的剩余有效期和归属用户,KEY设计为refresh:用户ID:令牌ID。当收到刷新请求,先查Redis确认未过期且未被吊销,再走JWT签发流程。
前端拿到刷新令牌过期的响应后,绝不要静默重试。正确做法是清除本地全部令牌缓存,弹出登录弹窗或跳转到登录路由,并带上当前页面地址,方便登录后回跳。如果产品允许,也可以提供一个“记住设备”的二次验证流程,用短信码或生物识别换发新令牌,避免输入密码。下面的前端示例展示了拦截器和过期处理:
// 请求响应拦截
axios.interceptors.response.use(
res => res,
async err => {
if (err.response && err.response.status === 401) {
const code = err.response.data && err.response.data.code;
if (code === 'refresh_token_expired') {
// 清除缓存并跳转登录
localStorage.removeItem('access_token');
window.location.href = '/login?redirect=' + encodeURIComponent(location.pathname);
return Promise.reject(err);
}
}
return Promise.reject(err);
}
);
此外,建议在监控面板里统计刷新令牌过期的比例。如果突然飙升,可能是服务端时钟不同步、密钥轮换失误或客户端时间错误。通过日志关联用户ID和设备,能快速定位是个例还是批量故障。把过期处理当作正常业务分支而非异常,才能构建稳健的认证体系。
JWTrefresh_tokentoken_expiration修改时间:2026-08-16 11:58:15