[jwt 做多用户表验证] jwt.auth 中间件一直报错找不到用户

环境

机器: CentOS release 6.10 (Final)
语言: PHP 7.2.24
框架: laravel 5.4
插件: tymon/jwt-auth 1.0

情景

一个 web 项目使用 tymon/jwt-auth 1.0 做 API 用户验证,用户表为自定义的 customer 表(user 表被用作后台用户表来用),用户登录可以正常使用,但是在登录后调用需检验登录状态的接口时会报错: UnauthorizedHttpException“User not found”(使用 jwt.auth 中间件)。

代码

 // config/auth.php
 'defaults' => [
     'guard' => 'web',
     'passwords' => 'users',
 ],
 'guards' => [
     'web' => [
         'driver' => 'session',
         'provider' => 'users',
     ],
     'api' => [
        // 'driver' => 'token',
        'driver' => 'jwt',
        'provider' => 'customers',
    ],
],
// 控制器中间件声明
public function __construct() {
    $this->middleware('jwt.auth', ['except' => ['login', 'refresh']]);
}

排查过程

  1. 找到中间件报错位置
    // Tymon\JWTAuth\Http\Middleware\BaseMiddleware
    /**
    * Attempt to authenticate a user via the token in the request.
    *
    * @param  \Illuminate\Http\Request  $request
    *
    * @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
    *
    * @return void
    */
    public function authenticate(Request $request) {
      $this->checkForToken($request);
      try {
          if (! $this->auth->parseToken()->authenticate()) {
              throw new UnauthorizedHttpException('jwt-auth', 'User not found');
          }
      } catch (JWTException $e) {
          throw new UnauthorizedHttpException(
              'jwt-auth',
              $e->getMessage(),
              $e,
              $e->getCode()
          );
      }
    }
    问题是 $this->auth->parseToken()->authenticate() 返回了 false
  2. 继续往下找
    // Tymon\JWTAuth\JWTAuth
    /**
    * Authenticate a user via a token.
    *
    * @return \Tymon\JWTAuth\Contracts\JWTSubject|false
    */
    public function authenticate() {
     $id = $this->getPayload()->get('sub');
     if (! $this->auth->byId($id)) {
         return false;
     }
     return $this->user();
    }
    此处 $this->auth->byId($id) 返回了 false 。什么?我的用户ID不存在?什么鬼,继续往下找。
  3. 继续往下找
    // Tymon\JWTAuth\Providers\Auth\Illuminate
    ...
    use Illuminate\Contracts\Auth\Guard as GuardContract;
    ...
    public function __construct(GuardContract $auth) {
     $this->auth = $auth;
    }
    ...
    /**
    * Authenticate a user via the id.
    * @param  mixed  $id
    * @return bool
    */
    public function byId($id) {
     return $this->auth->onceUsingId($id);
    }
    明显是这个 Guard 的实例并不是我们想要的,打出来看看他是什么鬼:Illuminate\Auth\SessionGuard,原形毕露,我们的中间件最后使用的 guard 是SessionGuard

问题

它调用 SessionGuard 去找的话会查到默认的 user 表中,能有这个ID就有鬼了。
那么,是我哪里搞错了呢?

各位大佬帮帮我,不胜感激

《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 6

要么默认的guard 改成api

 // config/auth.php
 'defaults' => [
     'guard' => 'api',
     'passwords' => 'users',
 ],

要么中间件增加对应的guard

// 控制器中间件声明
public function __construct() {
    $this->middleware('auth:api', ['except' => ['login', 'refresh']]);
}
1周前 评论
liuwq (楼主) 1周前
岁月流沙 1周前
liuwq (楼主) 1周前

有配置 User Providers吗 没有的话参考这个配置。

// config/auth.php
...
'providers' => [
...
        'customers' => [
            'driver' => 'eloquent',
            'model' => App\Customers::class,   // customers 对应的模型
        ]
...
    ],
1周前 评论
liuwq (楼主) 1周前
public function authenticate() {
 $id = $this->getPayload()->get('sub');
 if (! $this->auth->byId($id)) {
     return false;
 }
 return $this->user();
}

可以在 if 的地方下个断点看auth是哪个类被传进来了,这个类是不是没实现GuardContract接口

1周前 评论
liuwq (楼主) 1周前

我也遇到了这个问题,期待解答

1周前 评论
liuwq (楼主) 1周前
littledragoner (作者) 1周前
liuwq (楼主) 1周前
xiaohuasheng

把 guards的api和web的位置换一下试试,api放在first。 参考:docs.spatie.be/laravel-permission/...

5天前 评论
liuwq (楼主) 4天前

试试中间件改成 auth.api
我的配置和你一样的,管理后台用的jwt接口认证,web端用的session。只是中间件使用不一样。

Route::group([
    'middleware' => 'auth:api'
],function(){
});
4天前 评论
liuwq (楼主) 4天前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!