Laravel JWT令牌过期未自动刷新问题咨询
解决Laravel JWT令牌过期后未自动刷新的问题
我之前也碰到过一模一样的问题,你控制器里写的TokenExpiredException捕获逻辑没生效,核心原因是**jwt.auth中间件会在你的控制器代码执行前先验证令牌**——当令牌过期时,中间件已经抛出了异常,根本轮不到控制器里的catch块来处理。下面给你几个可行的解决方案:
方案一:自定义JWT认证中间件处理刷新
替代默认的jwt.auth中间件,自己实现包含令牌刷新逻辑的认证流程:
- 创建自定义中间件:
php artisan make:middleware JwtAuthenticate
- 在
app/Http/Middleware/JwtAuthenticate.php中编写逻辑:
<?php namespace App\Http\Middleware; use Closure; use Tymon\JWTAuth\Facades\JWTAuth; use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Tymon\JWTAuth\Exceptions\TokenInvalidException; use Tymon\JWTAuth\Exceptions\JWTException; class JwtAuthenticate { public function handle($request, Closure $next) { try { // 尝试验证令牌并获取用户 $user = JWTAuth::parseToken()->authenticate(); if (!$user) { return response()->json(['user_not_found'], 404); } } catch (TokenExpiredException $e) { // 令牌过期,尝试刷新 try { $refreshedToken = JWTAuth::refresh(JWTAuth::getToken()); // 将刷新后的令牌添加到响应头,方便客户端获取 $response = $next($request); $response->headers->set('Authorization', 'Bearer ' . $refreshedToken); return $response; } catch (JWTException $e) { // 刷新令牌也失败(比如refresh_ttl也过期了) return response()->json(['token_expired_and_cannot_refresh'], 401); } } catch (TokenInvalidException $e) { return response()->json(['token_invalid'], 401); } catch (JWTException $e) { return response()->json(['token_absent'], 400); } return $next($request); } }
- 在
app/Http/Kernel.php中注册中间件:
protected $routeMiddleware = [ // ...其他中间件 'jwt.custom' => \App\Http\Middleware\JwtAuthenticate::class, ];
- 修改路由使用自定义中间件:
Route::group(['middleware' => 'jwt.custom'], function () { Route::get('account/getUserDetails', 'Api\AccountController@getUserDetails'); });
方案二:全局异常处理器捕获TokenExpiredException
在全局异常处理中捕获令牌过期异常,并返回刷新后的令牌:
- 编辑
app/Exceptions/Handler.php:
use Tymon\JWTAuth\Exceptions\TokenExpiredException; use Tymon\JWTAuth\Facades\JWTAuth; // ... public function render($request, Throwable $exception) { if ($exception instanceof TokenExpiredException) { try { $refreshedToken = JWTAuth::refresh(JWTAuth::getToken()); return response()->json([ 'message' => 'Token refreshed', 'token' => $refreshedToken ], 200); } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) { return response()->json(['error' => 'token_expired_and_cannot_refresh'], 401); } } return parent::render($request, $exception); }
额外注意事项
- 确认你的
config/jwt.php中refresh_ttl设置正确(你当前设的20160分钟=14天,是合理的),这个值决定了过期令牌能被刷新的最长时间。 - 客户端收到刷新后的令牌后,必须替换本地存储的旧令牌,后续请求都使用新令牌,否则会一直触发过期异常。
- 如果你坚持要在控制器里处理,需要确保路由不使用
jwt.auth中间件,而是自己在控制器开头手动执行令牌验证逻辑,但这种方式不如中间件优雅。
内容的提问来源于stack exchange,提问作者sk4yb3n
相关产品推荐
相关产品推荐

