本文目录导读:

令牌过期配置需要平衡安全性与用户体验,以下是一些合理配置的核心原则、常见场景建议及具体实施方案。
核心原则:分层设计与动态调整
- Access Token(访问令牌):短寿命、高频使用,用于验证每一次API请求。
- 目的:即使令牌泄露,攻击者能利用的时间窗口极短。
- 典型时长:15分钟 到 1小时。
- Refresh Token(刷新令牌):长寿命、低频使用,仅用于获取新的Access Token。
- 目的:用户无需频繁登录,长期保持会话。
- 典型时长:7天 到 30天,甚至更长(根据安全级别)。
- 滑动过期策略(Sliding Expiration):用户持续活跃时,自动延长会话。
- 目的:避免用户在使用中途突然被踢下线。
- 实现:
- 每次用户操作时,Reset Refresh Token的过期时间。
- 设置最长绝对过期时间(30天),防止永不失效的风险。
不同场景下的推荐配置
| 应用场景 | Access Token 有效期 | Refresh Token 有效期 | 策略侧重 | 备注 |
|---|---|---|---|---|
| 金融/支付类App | 5-15 分钟 | 1-3 天 | 高安全性 | 大额操作需二次验证。 |
| 企业内部系统(SaaS) | 30分钟 - 1小时 | 8小时 - 1天(工作时段) | 平衡 | 配合公司IT策略(如VPN、设备管理)。 |
| 社交媒体/论坛 | 1小时 - 4小时 | 7天 - 30天 | 用户体验优先 | 用户长时间不活跃才需重新登录。 |
| 移动端原生App | 15-30分钟 | 30天 - 90天 | 长会话 | App被卸载或登录设备改变时需清除Token。 |
| 单页应用(SPA/网页) | 建议更短 (5-10分钟) | 使用HttpOnly Cookie存储 | 防XSS攻击 | 避免Token泄露给前端JS;建议用/api/refresh专用端点。 |
合理配置的具体实施
令牌生成与存储
- Access Token:
- 用户ID、权限(scope)、过期时间(
exp)、颁发者(iss)。 - 存储(前端):
- 移动端:存放在系统安全存储(iOS Keychain / Android KeyStore)。
- Web端:强烈建议使用HttpOnly、Secure、SameSite=Strict的Cookie,如果必须存localStorage,务必配合短过期时间+严格CSP策略。
- 用户ID、权限(scope)、过期时间(
- Refresh Token:
- 随机生成的唯一标识符(
jti)、用户ID、过期时间。 - 存储(后端):存储在数据库中(Redis或持久化DB),可以关联设备信息、IP地址。
- 传输:仅在刷新端点通过HTTPS传输。
- 随机生成的唯一标识符(
刷新流程(标准OAuth 2.0模式)
sequenceDiagram
participant Client
participant Server
participant DB
Client->>Server: API请求 (带Access Token)
Server->>Server: 验证Access Token
alt Token有效
Server-->>Client: 200 OK (返回数据)
else Token过期 (401)
Server-->>Client: 401 Unauthorized (错误码: TOKEN_EXPIRED)
Client->>Server: 发送Refresh Token至 /auth/refresh
Server->>Server: 验证Refresh Token有效性 & 是否被撤销
alt Refresh Token有效
Server->>DB: 更新或替换Refresh Token (可选)
Server-->>Client: 返回新的Access Token + 可选新的Refresh Token
Client->>Server: 重试原始API请求 (带新的Access Token)
else Refresh Token已过期/无效
Server-->>Client: 401/403 (要求用户重新登录)
end
end
关键细节:
- 轮换(Rotation):每次使用Refresh Token后,立即撤销旧Token并颁发新Token,这可以防止重放攻击。
- 重用检测(Reuse Detection):如果检测到旧的Refresh Token被再次使用(可能是Token泄露),立即撤销所有该用户的Refresh Token,并强制重新登录。
前端自动处理
在HTTP客户端(如Axios、Fetch)中实现拦截器,自动刷新令牌。
// 伪代码示例 (Vue/React + Axios)
let isRefreshing = false;
let failedQueue = [];
axios.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
// 如果正在刷新,将其他请求加入队列等待
return new Promise((resolve, reject) => {
failedQueue.push({ resolve, reject });
}).then(token => {
originalRequest.headers['Authorization'] = 'Bearer ' + token;
return axios(originalRequest);
});
}
originalRequest._retry = true;
isRefreshing = true;
try {
const { data } = await axios.post('/auth/refresh', { /* refreshToken */ });
const newToken = data.accessToken;
// 更新本地存储的Token (Cookie 或 内存)
setToken(newToken);
// 处理队列中的请求
failedQueue.forEach(prom => prom.resolve(newToken));
failedQueue = [];
// 重试原始请求
originalRequest.headers['Authorization'] = 'Bearer ' + newToken;
return axios(originalRequest);
} catch (refreshError) {
// 刷新失败:清除本地Token,跳转登录页
failedQueue.forEach(prom => prom.reject(refreshError));
failedQueue = [];
logout();
return Promise.reject(refreshError);
} finally {
isRefreshing = false;
}
}
return Promise.reject(error);
}
);
服务端验证与撤销
- Access Token:通常是自包含的(如JWT,使用非对称加密,Redis只做快速黑名单检查)。
- 检查:验证签名、
exp、iss、aud。
- 检查:验证签名、
- Refresh Token:必须进行状态检查(因为需要支持撤销)。
- 存储:使用Redis,设置
TTL(过期时间)与Refresh Token一致。 - 撤销场景:
- 用户主动登出
- 密码修改
- 检测到异常IP/设备
- 管理员强制下线
- 达到最大并发会话数
- 黑名单:对于短有效期的Access Token,可以不做全局黑名单;对于有撤销需求的Access Token,使用短有效期的Redis黑名单。
- 存储:使用Redis,设置
需要避免的配置陷阱
- Access Token 设置过长(>24小时)
- 风险:泄露后窗口太长,且无法在服务器端轻易撤销(除非维护庞大黑名单)。
- Refresh Token 永不过期或不轮换
- 风险:一旦泄露,攻击者可以永久维持会话。
- 客户端存储敏感Token
- 风险:localStorage易受XSS攻击。Cookie(HttpOnly+Secure)是最安全的Web存储方式。
- 前后端使用异步时钟(Clock Skew)
- 对策:服务器端验证
exp时,允许几秒(如30秒)的误差。
- 对策:服务器端验证
- 忽略滑动过期中的“绝对过期”
- 对策:设置
max_age(最长绝对时长),在Redis中单独记录用户的第一次登录时间或设置一个最晚过期点。
- 对策:设置
合理配置的推荐方案总结
| 配置项 | 推荐值/方法 | 理由 |
|---|---|---|
| Access Token 有效期 | 15-30 分钟 | 短窗口降低泄露风险 |
| Refresh Token 有效期 | 7-30 天 (根据场景) | 平衡安全与便利 |
| 滑动过期 | 是(每次请求刷新) + 绝对最长7-30天 | 避免不活跃会话永不过期 |
| Refresh Token 轮换 | 是(每次使用时刷新) | 检测并阻止Token重用 |
| 存储方式(Web) | HttpOnly Secure SameSite=Strict Cookie | 防XSS & CSRF |
| 存储方式(移动端) | 系统安全存储区 (Keychain/KeyStore) | 硬件级别安全 |
| 撤销机制 | 在Redis中管理Refresh Token状态 | 支持立即下线、密码修改等 |
令牌配置没有银弹,建议根据业务风险等级设定多个级别(如默认15分钟、高风险操作5分钟),并利用滑动过期和Refresh Token轮换这两项技术来有效抵御常见攻击(如Token窃取和重放)。