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下的路由默认已经加载该中间件组,重复配置没有意义。
修复步骤
- 修改认证中间件逻辑,适配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'); }
- 清理冗余路由配置
修改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'); }); });
- 配置请求头验证
请求API时携带Accept: application/json请求头,Laravel会自动适配JSON响应格式,不会尝试触发页面重定向。修改完成后传入无效token测试,接口会正常返回401状态码和对应JSON错误信息,不会再抛出路由相关异常。
内容的提问来源于stack exchange,提问作者siavash
相关产品推荐
相关产品推荐

