同じlaravelプロジェクトに複数の端末(モバイル端末、管理端末など)があり、すべてユーザーにjwtを使用する必要がある場合検証では、複数のユーザーテーブルがある場合(通常は存在します)、トークンの分離を行う必要があります。そうしないと、モバイル側のトークンも管理側に要求でき、ユーザーが権限を超えてしまうという問題が発生します。
この問題が発生する理由は、laravel の jwt トークンがデフォルトでデータテーブルの主キーの値のみを格納し、どのテーブルであるかを区別しないためです。したがって、トークンに含まれる ID がユーザー テーブルに存在する限り、不正な検証が行われてしまいます。
laravel の jwt トークンの元の外観を見てみましょう:
{ "iss": "http://your-request-url", "iat": 1558668215, "exp": 1645068215, "nbf": 1558668215, "jti": "XakIDuG7K0jeWGDi", "sub": 1, "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd" }
データを運ぶサブフィールドはサブフィールドで、他のフィールドは jwt の検証フィールドです。
sub の値が 1 であることがわかるだけで、それがどのテーブルまたはバリデーターに属しているかは示されません。このトークンが検証ミドルウェアを通過すると、さまざまなガードを使用して、対応するテーブル ID 1 を持つユーザーを取得できます (ガードについて詳しくは、laravel のドキュメントを確認してください)。
ユーザーのオーバーリーチの問題を解決するには、トークンにカスタム フィールドを追加して、どのテーブルまたはバリデータがトークンを生成したかを区別し、それを検証する独自のミドルウェアを作成するだけです。カスタムフィールドは私たちの期待と一致しています。
jwt 検証を使用するには、ユーザー モデルが JWTSubject インターフェイスを実装する必要があることがわかっています (コードは jwt ドキュメントから取得されます):
<?php namespace App; use Tymon\JWTAuth\Contracts\JWTSubject; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable implements JWTSubject { use Notifiable; // 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 []; } }
これら 2 つの実装されたメソッドの機能を見てみましょう:
次に、getJWTCustomClaims メソッドを実装するユーザー モデルにカスタム情報を追加できます。
管理者モデル:
/** * 额外在 JWT 载荷中增加的自定义内容 * * @return array */ public function getJWTCustomClaims() { return ['role' => 'admin']; }
モバイル ユーザー モデル:
/** * 额外在 JWT 载荷中增加的自定义内容 * * @return array */ public function getJWTCustomClaims() { return ['role' => 'user']; }
ここにユーザー ID としてロール名が追加されます。
管理者によって生成されたトークンは次のようになります:
{ "iss": "http://your-request-url", "iat": 1558668215, "exp": 1645068215, "nbf": 1558668215, "jti": "XakIDuG7K0jeWGDi", "sub": 1, "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd", "role": "admin" }
モバイル ユーザーによって生成されたトークンは次のようになります:
{ "iss": "http://your-request-url", "iat": 1558668215, "exp": 1645068215, "nbf": 1558668215, "jti": "XakIDuG7K0jeWGDi", "sub": 1, "prv": "92d5e8eb1b38ccd11476896c19b0e44512b2aacd", "role": "user" }
追加された役割フィールドは、ユーザー モデルに対応します。
次に、ミドルウェアを自分で書きます。トークンを解析した後、それが必要な役割であるかどうかを判断します。一致する場合はパスし、一致しない場合は 401 を報告します。
これはグローバルに使用可能なミドルウェアです (ユーザー検証ミドルウェアの前に使用することをお勧めします):
<?php /** * Created by PhpStorm. * User: wlalala * Date: 2019-04-17 * Time: 13:55 */ namespace App\Http\Middleware; use Closure; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; use Tymon\JWTAuth\Exceptions\JWTException; use Tymon\JWTAuth\Http\Middleware\BaseMiddleware; class JWTRoleAuth extends BaseMiddleware { /** * Handle an incoming request. * * @param $request * @param Closure $next * @param null $role * @return mixed */ public function handle($request, Closure $next, $role = null) { try { // 解析token角色 $token_role = $this->auth->parseToken()->getClaim('role'); } catch (JWTException $e) { /** * token解析失败,说明请求中没有可用的token。 * 为了可以全局使用(不需要token的请求也可通过),这里让请求继续。 * 因为这个中间件的责职只是校验token里的角色。 */ return $next($request); } // 判断token角色。 if ($token_role != $role) { throw new UnauthorizedHttpException('jwt-auth', 'User role error'); } return $next($request); } }
app/Http/Kernel.php にミドルウェアを登録します:
/** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ // ...省略 ... // 多表jwt验证校验 'jwt.role' => \App\Http\Middleware\JWTRoleAuth::class, ];
次に、ユーザー検証が必要なルートを追加します。ミドルウェアをグループに追加します。
Route::group([ 'middleware' => ['jwt.role:admin', 'jwt.auth'], ], function ($router) { // 管理员验证路由 // ... }); Route::group([ 'middleware' => ['jwt.role:user', 'jwt.auth'], ], function ($router) { // 移动端用户验证路由 // ... });
これで、jwt の複数テーブルのユーザー検証の分離が完了しました。
Laravel 関連の技術記事の詳細については、Laravel チュートリアル 列にアクセスして学習してください。
以上がLaravel jwtマルチテーブル検証分離の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。