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

Laravel8使用tymon/jwt-auth未授权返回500报login路由未定义

Laravel 8 JWT认证错误token返回500、login路由不存在问题解决

环境与故障现象

  • 运行环境:Laravel 8,JWT扩展版本tymon/jwt-auth ^1.0
  • 预配置:系统默认guard设为api,api guard驱动为jwt
  • 故障表现:传入无效token请求受保护接口时,返回500状态码,抛出Route [login] not defined异常;手动将登录路由命名为login后,又触发「路由不支持GET方法」报错,但登录路由本身定义为POST类型。

关联代码

路由文件routes/api.php

Route::group(['prefix'=>'v1'],function (){
    Route::group([
        'middleware' => 'api',
        'prefix' => 'auth'
    ], function ($router) {
        Route::post('login', 'App\Http\Controllers\AuthController@login');
        Route::post('logout', 'App\Http\Controllers\AuthController@logout');
        Route::post('refresh', 'App\Http\Controllers\AuthController@refresh');
        Route::post('me', 'App\Http\Controllers\AuthController@me');
    });

});

控制器文件app/Http/Controllers/AuthController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\Controller;

class AuthController extends Controller
{
    /**
     * Create a new AuthController instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login']]);
    }

    /**
     * Get a JWT via given credentials.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);

        if (! $token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        return $this->respondWithToken($token);
    }

    /**
     * Get the authenticated User.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(auth()->user());
    }

    /**
     * Log the user out (Invalidate the token).
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function logout()
    {
        auth()->logout();

        return response()->json(['message' => 'Successfully logged out']);
    }

    /**
     * Refresh a token.
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(auth()->refresh());
    }

    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth()->factory()->getTTL() * 60
        ]);
    }
}

模型文件app/Models/User.php

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    // Rest omitted for brevity

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }
}

原始报错信息

Symfony\Component\Routing\Exception\RouteNotFoundException: Route [login] not defined. in file C:\wamp64\www\medrep-app\vendor\laravel\framework\src\Illuminate\Routing\UrlGenerator.php on line 444

🧨 Route [login] not defined

故障根因

Laravel自带的auth中间件默认是为Web页面场景设计的:认证失败时会自动发起GET重定向,跳转到名为login的路由。

  • 没有定义名为login的路由时,就会抛出路由不存在的500错误;
  • 手动给POST类型的登录路由命名为login后,重定向的GET请求和路由的POST方法不匹配,就会触发请求方法不支持的报错。
    本质问题是API场景下不需要页面重定向逻辑,认证失败应该直接返回401状态码的JSON响应,而不是跳转路由。另外路由组里重复挂载了api中间件,api.php下的路由默认已经加载该中间件组,重复配置没有意义。

修复步骤

  1. 修改认证中间件逻辑,适配API场景
    打开app/Http/Middleware/Authenticate.php,重写redirectTo方法,让API前缀的请求认证失败时直接返回JSON响应,不做路由跳转:
protected function redirectTo($request)
{
    // API请求直接返回401 JSON,不重定向
    if ($request->is('api/*') || $request->expectsJson()) {
        abort(response()->json([
            'error' => 'Unauthenticated'
        ], 401));
    }
    // 非API请求保留原有跳转逻辑
    return route('login');
}
  1. 清理冗余路由配置
    修改routes/api.php,去掉重复挂载的api中间件,不需要给登录路由设置login命名:
Route::group(['prefix'=>'v1'],function (){
    Route::group([
        'prefix' => 'auth'
    ], function () {
        Route::post('login', 'App\Http\Controllers\AuthController@login');
        Route::post('logout', 'App\Http\Controllers\AuthController@logout');
        Route::post('refresh', 'App\Http\Controllers\AuthController@refresh');
        Route::post('me', 'App\Http\Controllers\AuthController@me');
    });
});
  1. 配置请求头验证
    请求API时携带Accept: application/json请求头,Laravel会自动适配JSON响应格式,不会尝试触发页面重定向。修改完成后传入无效token测试,接口会正常返回401状态码和对应JSON错误信息,不会再抛出路由相关异常。

内容的提问来源于stack exchange,提问作者siavash

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:09:28