Laravel 6.x 版本中,如果 JWT 不正确的时不会抛出 401
L03 Laravel 教程 - 实战构架 API 服务器 ( Laravel 6.x ) 一书中 5.1. 获取用户信息,如果 jwt token 失效,报错 Route [login] not defined. 问题分析
报错情况
- 如果当前项目中没有定义 login 路由时( 不管是 web.php 或者 api.php 中都没有定义 login 路由)会报错
Route [login] not defined.
- 如果当前项目中有定义 login 路由时,jwt token 失效的话会报错
"message": "Unauthenticated."
我当时以为是我的哪里操作不对,直到我将课程源码下下来之后,测试一下发现确实不是我的操作问题
错误重现
- 当 jwt token 为正确的时候,发现我们是可以正常获取到用户信息的。如下图所示
- 故意将 jwt token 改成错误的,就会报错,但是并非报 401 错误
- 如果你项目中没有路由名称为 login 的路由时,会报错
报错分析
- 我们是通过
auth:api
中间件来判断用户是否已经登录的,那么此时我们定位到App\Http\Kernel.php
文件中
- 然后我们继续定位到
App\Http\Middleware\Authenticate.php
文件中
我们可以看到 \App\Http\Middleware\Authenticate::class@redirectTo
方法,当不是 ajax
请求的时候,就跳转到了 login
路由,那么 "message": "Unauthenticated."
又是如何产生的 呢?
- 我们发现
\App\Http\Middleware\Authenticate
类 继承了Illuminate\Auth\Middleware\Authenticate
类,那么我们继续定位到Illuminate\Auth\Middleware\Authenticate
中
- 因为是中间件,因此我们直接看
Illuminate\Auth\Middleware\Authenticate::class@handle
方法
继而我们可以看到如果登录验证失败的话就直接抛出 AuthenticationException
异常了
解决方案
重新自定义一个路由中间件,自己实现登录验证
- 执行以下
artisan
命令,生成CheckUserLogin
中间件文件
php artisan make:middleware CheckUserLogin
- 在
App\Http\Middleware\CheckUserLogin::class@handle
方法中写登录验证逻辑
- 在
App\Http\Kernel
中注册路由中间件
- 使用刚刚自定义的验证登录路由,在路由文件中
// 登录后可以访问的接口
Route::middleware(['checkUserLogin'])->group(function() {
// 当前登录用户信息
Route::get('user', 'Auth\UsersController@me')->name('user.show');
Route::get('tests', 'Api\ApiTestsController@index')->name('tests.index');
});
以上是我目前的解决方案,如果你有其它的解决方案,或者以上我理解有问题,还望指正!
20200209 更新
我的业务场景是想授权验证失败,框架就能够直接给我返回一段以下这样的数据
{
"code": 401,
"msg": "登录已过期,请重新登录"
)
但是框架是直接返回了
{"message": "Unauthenticated."}
不符合我自己的数据格式要求,因此需要在 app\Exceptions\Handler.php
文件中做一下处理。非常感谢课程作者 liyu001989
的指点。👍
重现不了,你先确定一下 header 到底对不对。真的需要手动处理,也是在 app/Exceptions/Handler.php 里面处理