You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel JWT令牌过期未自动刷新问题咨询

解决Laravel JWT令牌过期后未自动刷新的问题

我之前也碰到过一模一样的问题,你控制器里写的TokenExpiredException捕获逻辑没生效,核心原因是**jwt.auth中间件会在你的控制器代码执行前先验证令牌**——当令牌过期时,中间件已经抛出了异常,根本轮不到控制器里的catch块来处理。下面给你几个可行的解决方案:

方案一:自定义JWT认证中间件处理刷新

替代默认的jwt.auth中间件,自己实现包含令牌刷新逻辑的认证流程:

  1. 创建自定义中间件:
php artisan make:middleware JwtAuthenticate
  1. 在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);
    }
}
  1. 在app/Http/Kernel.php中注册中间件:
protected $routeMiddleware = [
    // ...其他中间件
    'jwt.custom' => \App\Http\Middleware\JwtAuthenticate::class,
];
  1. 修改路由使用自定义中间件:
Route::group(['middleware' => 'jwt.custom'], function () {
    Route::get('account/getUserDetails', 'Api\AccountController@getUserDetails');
});

方案二:全局异常处理器捕获TokenExpiredException

在全局异常处理中捕获令牌过期异常,并返回刷新后的令牌:

  1. 编辑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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:43:43