使用 JWT 時,新增自定義資料並在登陸時校驗

yyy123456發表於2021-04-27

需求如下

同一個使用者有兩種角色,分別定義了是否可以禁止登陸即凍結。
應用登陸時,需要選擇角色,然後才點選登陸按鈕。
當後臺設定該使用者的某個角色凍結時,需要禁止該角色使用我們的應用程式。

解決思路

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 中新增自定義資料了!

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章