LoginSignup
9
8

More than 3 years have passed since last update.

Laravel tymon/jwt-auth のブラックリストをデータベースに保存する

Last updated at Posted at 2019-10-24

Laravel/Lumen 用の JWT 認証パッケージである tymon/jwt-auth では、発行した有効なトークンを保持するのではなく、ログアウトしたりリフレッシュされた古いトークンをブラックリストという形で保存しておく。デフォルトではキャッシュに保存されるので、Redis などで共有していないとスケールアウトできない。ということで、データベースに保存してみる。

環境

手順

テーブル jwt_auth_storage を作成

database/migrations 配下に定義してマイグレーションする。

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateJwtAuthStorageTable extends Migration
{
    public function up(): void
    {
        Schema::create('jwt_auth_storage', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
            $table->timestamp('expires_at')->nullable();
            $table->string('key')->index();
            $table->string('value');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('jwt_auth_storage');
    }
}

jwt_auth_storage テーブルの Eloquent Model を作成

<?php
namespace App\Model;

use Illuminate\Database\Eloquent\Model;

class JwtAuthStorage extends Model
{
    protected $table = 'jwt_auth_storage';

    protected $fillable = [
        'key', 'value', 'expires_at',
    ];

    protected $dates = ['expires_at'];
}

Storage を継承したアクセスクラスを作成

Tymon\JWTAuth\Contracts\Providers\Storage を継承し、各メソッドを実装したクラスを作成する。デフォルトでは Tymon\JWTAuth\Providers\Storage\Illuminate::class が使用されるので、これを参考にする。

<?php
namespace App\Repository;

use App\Model\JwtAuthStorage;
use DateTime;
use Tymon\JWTAuth\Contracts\Providers\Storage;

class JwtAuthStorageRepository implements Storage
{
    protected $jwtAuthStorageModel;

    public function __construct(JwtAuthStorage $jwtAuthStorageModel)
    {
        $this->jwtAuthStorageModel = $jwtAuthStorageModel;
    }

    public function add($key, $value, $minutes): void
    {
        $expiresAt = (new DateTime('now'))->modify('+ ' . $minutes . ' minutes');
        $this->jwtAuthStorageModel->newQuery()
            ->create([
                'key' => $key,
                'value' => serialize($value),
                'expires_at' => $expiresAt,
            ]);
    }

    public function forever($key, $value): void
    {
        $this->jwtAuthStorageModel->newQuery()
            ->create([
                'key' => $key,
                'value' => serialize($value),
            ]);
    }

    public function get($key)
    {
        $now = new DateTime('now');
        $data = $this->jwtAuthStorageModel->newQuery()
            ->where('key', $key)
            ->where('expires_at', '>', $now)
            ->orderBy('expires_at', 'desc')
            ->first();
        if ($data) {
            return unserialize($data->value);
        } else {
            return null;
        }
    }

    public function destroy($key): bool
    {
        return !!$this->jwtAuthStorageModel->newQuery()
            ->where('key', $key)
            ->delete();
    }

    public function flush()
    {
    }
}

設定ファイルを publish

設定を変更するため、config/jwt.php をプロジェクトに展開する。

$ php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

設定

設定ファイル(config/jwt.php)の provider.storage に、カスタマイズしたアクセスクラスを指定する。ブラックリストの読み書きはこのクラスを経由しておこなわれる。

<?php
return [
    ...
    'providers' => [
        ...
        'storage' => App\Repository\JwtAuthStorageRepository::class,
    ],
];
9
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
8