使用 JWT 时,添加自定义数据并在登陆时校验

Laravel框架
429
0
0
2022-04-11
标签   Laravel授权

使用 JWT 时,添加自定义数据并在登陆时校验

需求如下

同一个用户有两种角色,分别定义了是否可以禁止登陆即冻结。

应用登陆时,需要选择角色,然后才点击登陆按钮。

当后台设置该用户的某个角色冻结时,需要禁止该角色使用我们的应用程序。

解决思路

1、登陆时,在token的自定义数据中指明角色类型。

2、每当任何一个请求到来时,都检查token中保存的角色类型,然后都到角色表查数据库一次,如果此人此角色被禁止,就返回错误。

3、本方案的缺点是:每次请求都需查一次数据库,但这是应产品的要求,只要后台设置冻结,就立刻禁止用户使用。其实也有其他方案,本文是比较简单、快捷、有效的一种。

4、另外,本文使用的是广受好评的 tymon/jwt-auth

表结构

表:有用户表,有角色表。

角色表字段:用户 id(user_id),角色 type(role_type),是否冻结(is_valid)。

解决步骤1:添加User模型类的两个子类

比如建立 UserType1 这个类

额外说明,这里代码里的 role_type 这个键是自己起名字的,不需要和表中字段一致。但值需要表示正确的角色类型 role_type。

namespace App\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
class UserType1 extends User implements JWTSubject
{
    public function getJWTCustomClaims()
    {  
        return ['role_type'=>1];
    }
}

再建立 UserType2 这个类

namespace App\Models;
use Tymon\JWTAuth\Contracts\JWTSubject;
class UserType2 extends User implements JWTSubject
{
    public function getJWTCustomClaims()
    {  
        return ['role_type'=>2];
    }
}

请注意,不是角色表。

解决步骤2:添加一个查冻结功能的中间件 ,并在 Kernel.php 中指定顺序

中间件名字自定,比如叫 PubUser

Kernel.php

protected $routeMiddleware = [
  。。。
  'pubuser' => \App\Http\Middleware\PubUser::class,
  'jwt.auth' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
];

protected  $middlewarePriority = [
  \Tymon\JWTAuth\Http\Middleware\Authenticate::class,
  \App\Http\Middleware\PubUser::class,
];
class PubUser
{
   public function handle($request, Closure $next)
   {  

      $user_sub = 角色表::query()->where('user_id', $request->user()->id)
         ->where('role_type', JWTAuth::getClaim('role_type'))
        ->firstOrFail();
      if ($user_sub->is_valid != 1) {
         throw new JWTException('您的账号被冻结');
      }
      return $next($request);
   }
}

解决步骤3:登陆时,选择正确的子类

如下代码,当选择了正确的子类时,该子类的自定义数据将会被放到 JWT 的 token 中,然后就可以每次都读取自定义数据了。

public function success_login($user)
{
  // $user 必须是  UserType2 或 UserType1 的实例,决不能是 User 的实例 
  $new_token = auth()->login($user);

  return [
  'new_token' => $new_token,
  'expire_time' => time() + config('jwt.ttl') * 60,
  ];
}

解决步骤4:加载带有检查冻结功能中间件的路由

注意,下面的路由都是必须登陆后才能使用的。

登陆路由另外写。

api.php

Route::middleware(['jwt.auth', 'pubuser' ])->group(function () {
    Route::any('/route1', 'IndexController@route1' );
    Route::any('/route2', 'IndexController@route2' );
});

总的来说,就是轻松搞定。

妈妈再也不用担心我不知道怎么在 JWT 中添加自定义数据了!