Skip to main content

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

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,
],
];