上一章我们聊了 Token 时代的黎明(2012–2018):从简单 Token 到 JWT 的标准化爆发。前端开始接管认证状态,JWT 凭借无状态和自包含的魅力,成为 SPA、微服务和移动 API 的新宠。但进入 2018 年后,JWT 也暴露了更多实际痛点——尤其是安全性和可控性。
这一篇,我们进入 Token 时代的“巅峰期”(2018–2023)。这几年,工程师们发明了各种折衷方案来补 JWT 的短板:双 Token 机制成为标配,刷新流派百花齐放,黑名单 vs 无状态的战争打得火热。同时,浏览器安全特性(如 SameSite)和风控手段(如设备指纹)也集体升级。这是一个从“理想主义”到“实用主义”的过渡期,Token 模式达到了成熟,但也积累了隐痛。
1. 双 Token 方案的全面普及:Access Token + Refresh Token(2018–2020 事实标准)
2018 年左右,纯 JWT 的问题越来越明显:exp 太长不安全、太短用户体验差、无法主动失效(登出/封号/改密码)。
于是,OAuth 2.0 风格的双 Token 成为主流解决方案(其实 2012 年 OAuth 2.0 就提了,但直到 2018 年才在 JWT 项目中大规模落地)。
核心思路:
- Access Token(AT):短有效期(5–15 分钟)、用于 API 调用、JWT 格式(含权限/用户信息)
- Refresh Token(RT):长有效期(几天/周/月)、不透明字符串(GUID 或加密串)、用于刷新 AT、存 Redis/DB(关联用户 + 过期 + 使用次数限制)
典型流程:
- 登录成功 → 返回 AT + RT
- 前端存 AT(用于请求)、RT(用于刷新)
- AT 过期 → 用 RT 换新 AT(可选带新 RT)
- 后端校验 RT → 查 Redis/DB → 发新 AT
后端示例(Node.js + jsonwebtoken):
// 登录
const accessToken = jwt.sign({ userId, roles }, ACCESS_SECRET, { expiresIn: '15m' });
const refreshToken = uuid.v4();
redis.set(`rt:${refreshToken}`, JSON.stringify({ userId, expire: Date.now() + 7*86400000 }), 'EX', 7*86400);
res.json({ accessToken, refreshToken });
// 刷新
app.post('/refresh', (req, res) => {
const rt = req.body.refreshToken;
redis.get(`rt:${rt}`, (err, val) => {
if (!val) return res.status(401).send('Invalid RT');
const { userId } = JSON.parse(val);
const newAT = jwt.sign({ userId }, ACCESS_SECRET, { expiresIn: '15m' });
res.json({ accessToken: newAT });
});
});
优点:安全(短 AT 泄露影响小)、可控(后端删 RT 即下线)、用户无感(前端自动刷新)。
缺点:引入有状态(RT 需存储),违背 JWT “纯无状态”初心。
2018–2020 年,这套几乎成了所有中大型项目的标配(Auth0、Firebase Auth、Okta 等 SaaS 也大力推)。
2. 前端刷新 Token 的三种流派对比(2018–2023 百家争鸣)
双 Token 落地后,前端如何刷新成了热点。三大流派各有拥趸:
| 流派 | 描述 | 优点 | 缺点 / 场景限制 | 流行时期 / 框架示例 |
|---|---|---|---|---|
| 静默刷新 | 后台定时器每 N 分钟(< AT 过期时间)用 RT 刷新 AT,无需等 401 | 用户无感知、API 调用零延迟 | 定时器管理复杂(多标签/后台标签问题) | 2018–2020;React + Redux |
| 401 拦截后刷新 | Axios/Fetch 拦截 401 → 用 RT 刷新 → 重发原请求 | 简单、按需刷新(不浪费请求) | 有延迟(刷新失败需重登录)、并发请求竞争 | 2020–2023;Vue + Pinia |
| 预刷新 | AT 快过期时(剩余 1/3 时间)刷新;或在关键操作前预刷 | 平衡延迟与效率 | 需解析 AT exp(JWT 优势)、逻辑稍复杂 | 2021–2023;Next.js / Nuxt |
代码示例(401 拦截,Axios 最经典):
import axios from 'axios';
let isRefreshing = false;
let failedQueue = [];
axios.interceptors.response.use(res => res, err => {
if (err.response.status !== 401) return Promise.reject(err);
const originalReq = err.config;
if (isRefreshing) {
return new Promise((resolve, reject) => failedQueue.push({ resolve, reject, originalReq }));
}
isRefreshing = true;
return refreshToken() // 用 RT 发 /refresh
.then(newAT => {
localStorage.setItem('accessToken', newAT);
originalReq.headers.Authorization = `Bearer ${newAT}`;
failedQueue.forEach(({ resolve, originalReq }) => resolve(axios(originalReq)));
failedQueue = [];
isRefreshing = false;
return axios(originalReq);
})
.catch(refreshErr => {
failedQueue.forEach(({ reject }) => reject(refreshErr));
failedQueue = [];
isRefreshing = false;
// 重定向登录
return Promise.reject(refreshErr);
});
});
这个阶段,框架生态(如 react-query、vuex-persist、apollo-client)内置了这些机制,极大降低了前端门槛。
3. JWT 的三大流派战争(2019–2023):无状态 vs 有状态的哲学辩论
JWT 社区分成三派,争论焦点:要不要牺牲“无状态”换取“可控性”?
- 完全无状态派:反对黑名单,只用短 exp + RT。理由:JWT 本意就是无状态,Redis/DB 是倒退。代表:Serverless 项目、CDN 边缘验证场景。
- 短有效期 + 黑名单派:AT 短 exp + 黑名单(Redis 存失效 token)。理由:权衡安全与便利。痛点:黑名单膨胀(需定期清理)。2019–2021 年最流行。
- 不使用 JWT、用不透明 Token + Redis 派:干脆不用 JWT,AT 也用 GUID + Redis 查。理由:Payload 可读是隐患,自包含不值一提。代表:高安全 ToB 系统(如银行)。
黑名单示例(Redis):
// 失效时
redis.set(`blacklist:${oldAT}`, 'invalid', 'EX', remainingExpSeconds);
// 校验中间件
function validateToken(req, res, next) {
const at = extractToken(req);
if (redis.exists(`blacklist:${at}`)) return res.status(401);
try {
const decoded = jwt.verify(at, SECRET);
req.user = decoded;
next();
} catch (e) { res.status(401); }
}
这场战争到 2023 年也没分胜负——取决于项目规模、安全需求和架构。
4. 安全加固手段的集中爆发(2018–2023)
浏览器和社区在这一期集体发力,补 Token 的安全短板。
- SameSite Cookie 属性(2016 草案 → 2019 Chrome 强制 → 2020 普及):Lax(默认,防 CSRF)、Strict(最严)、None(需 Secure)。Token 放 Cookie 时必用。
- CSRF Token 新玩法:双重 Cookie(一个 HttpOnly Token、一个 JS 可读 CSRF Token)、Synchronizer Token(每个请求带随机 Token)。
- HttpOnly Cookie + 自定义 Header 混用:AT 放 HttpOnly Cookie(防 XSS),请求时浏览器自动带;或混用 Bearer Header。
- 设备指纹 + 浏览器指纹风控(2019–2023 流行):用 fingerprintjs 等库生成指纹,登录/刷新时校验。异常(如新设备)触发 MFA。
这些手段让 Token 体系更健壮,但也增加了复杂度。
5. 隐痛积累:Token 时代的瓶颈信号(2022–2023)
- 刷新机制复杂:多端同步 RT 难(Web + App)
- 黑名单/Redis 依赖:规模大时性能瓶颈
- XSS/CSRF 永不消亡:尽管加固,攻击面仍存
- 隐私法规(GDPR/CCPA):Payload 含个人信息成隐患
这些痛点推动了下一波变革:OAuth 2 + 第三方登录的深化。
小结:2018–2023 是 Token 时代的“成年礼”
双 Token + 刷新机制让 JWT 真正成熟,安全加固填补了早期坑。但折衷方案也暴露了 Token 的天生矛盾:无状态 vs 可控、安全 vs 便利。