Laravel JWT过期怎么刷新?一文详解Token刷新机制与实战方案
目录导读
- JWT过期刷新核心概念
- Laravel JWT刷新机制原理
- 基础刷新实现(Tyymon/JWT-Auth)
- 自动刷新与黑名单策略
- 客户端刷新流程设计
- 常见问题与问答
JWT过期刷新核心概念
在Laravel开发中,JWT(JSON Web Token)常用于API认证,但默认Token存在过期时间,当Token过期后,用户请求被拒绝(通常返回401状态码),此时需要通过“刷新令牌”机制,让用户无需重新登录即可获取新Token。

核心点:
- Access Token(短期,如15分钟)
- Refresh Token(长期,如7天)
- 刷新操作使用Refresh Token生成新的Access Token
Laravel JWT刷新机制原理
Laravel常用的JWT包是 tymon/jwt-auth,其刷新机制基于以下流程:
- 用户登录时,后端发放
access_token和refresh_token(实际上jwt-auth默认只返回一个token,需手动扩展) - 当Access Token过期,客户端携带Refresh Token请求
/api/auth/refresh端点 - 后端验证Refresh Token有效性(未过期、未加入黑名单)
- 生成新的Access Token并返回
注意:jwt-auth的 refresh() 方法默认会黑名单原Token,防止重复使用。
基础刷新实现(Tyymon/JWT-Auth)
步骤1:安装与配置
composer require tymon/jwt-auth:^2.0 php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
配置 config/jwt.php 中的 ttl(Access Token生存时间)和 refresh_ttl(Refresh Token生存时间)。
步骤2:创建刷新路由与控制器
// routes/api.php
Route::post('auth/refresh', [AuthController::class, 'refresh']);
// app/Http/Controllers/AuthController.php
use Tymon\JWTAuth\Facades\JWTAuth;
public function refresh(Request $request)
{
try {
// 从请求中获取当前token(旧token)
$oldToken = JWTAuth::getToken();
if (!$oldToken) {
return response()->json(['error' => 'Token not provided'], 401);
}
// 刷新token(旧token自动加入黑名单)
$newToken = JWTAuth::refresh($oldToken);
return response()->json([
'access_token' => $newToken,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
// Token已过期且无法刷新(例如refresh_ttl也过期)
return response()->json(['error' => 'Token is expired, please re-login'], 401);
} catch (Tymon\JWTAuth\Exceptions\JWTException $e) {
return response()->json(['error' => 'Token invalid'], 401);
}
}
步骤3:中间件保护路由
// 在路由中添加JWT中间件
Route::middleware('jwt.auth')->group(function () {
Route::post('auth/refresh', [AuthController::class, 'refresh']);
});
关键点:jwt.auth 中间件会验证Token是否过期,如果过期则抛出 TokenExpiredException,此时可在全局异常处理中返回401,客户端再调用刷新接口。
自动刷新与黑名单策略
1 黑名单机制
jwt-auth默认会在刷新时将旧Token加入黑名单,这意味着:
- 一个Token只能被刷新一次(除非使用
setRefreshFlow()标记) - 如果恶意用户盗用Refresh Token,原用户将失效
配置黑名单宽限期:
// config/jwt.php 'blacklist_grace_period' => 0, // 单位秒,0表示立即黑名单
2 自动刷新中间件
为了避免客户端频繁手动刷新,可创建中间件自动检测并刷新Token:
// app/Http/Middleware/JwtAutoRefresh.php
public function handle($request, Closure $next)
{
try {
$token = JWTAuth::parseToken()->authenticate();
return $next($request);
} catch (TokenExpiredException $e) {
try {
$newToken = JWTAuth::refresh(JWTAuth::getToken());
// 将新token放入响应header
$response = $next($request);
$response->headers->set('Authorization', 'Bearer ' . $newToken);
return $response;
} catch (TokenExpiredException $e) {
return response()->json(['error' => 'Refresh token expired'], 401);
}
}
}
注意:自动刷新会影响性能,建议仅在关键路由使用。
客户端刷新流程设计
1 双Token模式(推荐)
- 后端返回
access_token+refresh_token - 客户端存储两者(
refresh_token存到httpOnly cookie) - 当API返回401时,客户端自动用
refresh_token请求刷新接口 - 获取新
access_token后重试原请求
示例代码(Axios拦截器):
axios.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const { data } = await axios.post('/api/auth/refresh', {
refresh_token: localStorage.getItem('refresh_token')
});
localStorage.setItem('access_token', data.access_token);
originalRequest.headers.Authorization = `Bearer ${data.access_token}`;
return axios(originalRequest);
} catch (refreshError) {
// 刷新失败,跳转登录
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
2 单Token模式(简易)
仅使用一个Token,但设置较长的TTL(如1天),过期后重新登录,适合管理后台等低安全场景。
常见问题与问答
Q1:刷新Token时,旧的Access Token还能用吗?
A:默认jwt-auth会黑名单旧Token,使其立即失效,如果希望在黑名单前有一段宽限期(防止并发请求),可设置 'blacklist_grace_period' => 60(秒)。
Q2:Refresh Token泄露了怎么办?
A:
- 服务端可记录Refresh Token的设备指纹(如User-Agent)
- 一旦发现异常,立即将该Refresh Token加入黑名单(jwt-auth不支持直接黑名单字符串,需自定义)
- 推荐使用
laravel-sanctum替代,它原生支持Token撤销
Q3:为什么刷新后返回的Token与旧Token完全相同?
A:可能是 JWT_BLACKLIST_ENABLED=false 或黑名单被禁用,检查 .env 中 JWT_BLACKLIST_ENABLED 是否为 true。
Q4:多设备登录如何保证刷新不互踢?
A:
- 每个设备生成独立Token,刷新时只黑名单当前设备Token
- 使用Redis存储设备与Token映射,刷新时删除旧映射
Q5:如何让Refresh Token长期有效且不被盗用?
A:
- 使用
jwt.refresh_ttl控制最长有效期(如7天) - 结合
JWT_BLACKLIST_GRACE_PERIOD防止并发问题 - 服务端记录Refresh Token的最后使用时间,超过阈值要求重新认证
Laravel JWT刷新主要依赖 tymon/jwt-auth 的 refresh() 方法,结合黑名单机制确保安全性,实际项目建议采用双Token + 前端拦截器模式实现无感刷新,对于更高安全要求,可考虑使用 laravel/sanctum 或OAuth2方案。
核心优化点:
- 合理设置TTL(Access 15分钟,Refresh 7天)
- 启用黑名单 + 宽限期
- 客户端使用拦截器自动重试
- 记录Refresh Token的使用日志用于审计
通过以上方案,即可在Laravel应用中实现安全高效的JWT过期刷新机制。