Yii框架RESTful接口默认不提供Token刷新机制,需手动实现refresh接口并配合前端处理401错误;推荐用Redis存储绑定用户、时效与次数的refresh_token,验证后签发短效access_token。

Yii框架的RESTful接口本身不内置Token刷新机制,所谓“刷新令牌”必须由你手动实现逻辑、配合前端协作,否则401错误后只能重新登录。
为什么Yii默认没有Refresh Token流程
Yii的yii\filters\auth\HttpBearerAuth或QueryParamAuth只做单次验证:收到Token就解码JWT、查用户、验签名和过期时间,通过则放行,不通过直接返回401。它不关心“这个Token快过期了要不要换一个”,更不会自动下发新Token。
这意味着:
- 前端拿到的
access_token一旦过期,下次请求就会被拦在过滤器外,无法触发任何续期逻辑 - 若依那种“每次请求顺带刷新”的滑动过期,是业务层主动写在拦截器里的,Yii原生不提供
- 你看到的“刷新令牌”功能,几乎全是项目自己在
Controller里额外加的refresh动作,比如POST /api/v1/auth/refresh
如何手动实现一个安全的refresh接口
关键不是生成新Token,而是控制刷新权限——不能让任意过期Token都能无限续期。
推荐做法:
- 用Redis存一份
refresh_token(非JWT,是随机字符串),绑定用户ID + 过期时间(如7天)+ 使用次数限制(如最多续3次) -
refresh接口只接受这个refresh_token,验证通过后才签发新的access_token(有效期30分钟)并更新Redis中对应记录 - 旧
access_token不用主动作废,JWT本身过期即失效;但refresh_token用一次就应更新或删除,防止重放 - 在
refresh成功响应头中返回Set-Cookie: refresh_token=xxx; HttpOnly; Secure; SameSite=Strict,避免JS读取泄露
示例控制器逻辑片段:
public function actionRefresh()
{
$refreshToken = Yii::$app->request->get('refresh_token');
$stored = Yii::$app->cache->get('refresh:' . $refreshToken);
if (!$stored || $stored['user_id'] != Yii::$app->user->id) {
throw new UnauthorizedHttpException('Invalid refresh token');
}
// 签发新 access_token
$newToken = JwtHelper::generateToken(['uid' => $stored['user_id']], 1800); // 30分钟
// 更新 refresh_token 记录(可选:换新值 + 重置计数)
Yii::$app->cache->set('refresh:' . $refreshToken, $stored, 604800); // 7天
return ['access_token' => $newToken];
}
前端调用refresh时容易踩的三个坑
后端写了接口,前端没配合好,照样白搭。
- 没捕获401就直接跳登录页:应在全局HTTP拦截器里监听
status === 401且响应体含"code": "token_expired"这类标识,再触发refresh,而不是无差别跳转 - 并发请求导致多次refresh:用户快速点两个按钮,可能发出两个refresh请求,第二个会因第一个已消耗
refresh_token而失败。需加锁或节流,例如用Promise缓存正在pending的refresh请求 - 没更新本地存储的Token:refresh成功后,必须同步更新
localStorage.setItem('access_token', ...)和axios.defaults.headers.common['Authorization'],否则下个请求还是拿旧Token
别碰“永不过期”的access_token
有团队为省事把JWT的exp设成0或极大值,这等于放弃时效性防护。只要Token泄露,攻击者就能永久冒充——尤其在RESTful场景下,Token常被存在localStorage,XSS漏洞即可直接盗取。
真正该延长的是refresh_token生命周期(比如7天),而access_token保持短时效(15–30分钟),这才是平衡安全与体验的合理边界。滑动过期也好、定时刷新也罢,核心都是让活跃用户免打扰,而不是让Token本身变“不死”。


















