トークン認証システムの実装と切り替え
トークン認証システムをMySQLからRedisに将来的に移行する場合、シームレスな切り替えを実現する方法を説明します。
インターフェースの定義
まずトークン操作のインターフェースを定義します:app/Contracts/TokenService.php
<?php
namespace App\Contracts;
interface TokenService
{
/**
* ユーザーIDに基づいて新しいトークンを生成
*/
public function generateToken(int $userId): string;
/**
* トークンから対応するユーザー情報を取得
*/
public function getUserByToken(string $token);
/**
* 指定されたトークンを削除
*/
public function deleteToken(string $token): bool;
}
MySQL実装クラス
MySQL用の実装クラスを作成します:app/Implementations/MySqlTokenService.php
<?php
namespace App\Implementations;
use App\Contracts\TokenService;
use App\Models\Token;
class MySqlTokenService implements TokenService
{
private const MAX_TOKENS_PER_USER = 10;
public function generateToken(int $userId): string
{
$userTokens = Token::where('user_id', $userId);
if ($userTokens->count() >= self::MAX_TOKENS_PER_USER) {
$userTokens->oldest('updated_at')->first()->delete();
}
$newToken = \Illuminate\Support\Str::random(32);
Token::create(['token' => $newToken, 'user_id' => $userId]);
return $newToken;
}
public function getUserByToken(string $token)
{
$tokenRecord = Token::with('user')->where('token', $token)->first();
return $tokenRecord->user ?? null;
}
public function deleteToken(string $token): bool
{
return (bool) Token::where('token', $token)->delete();
}
}
サービスバインディングの設定
bootstrap/app.phpでインターフェースと実装クラスの紐付けを行います:
$app->bind(
\App\Contracts\TokenService::class,
\App\Implementations\MySqlTokenService::class
);
コントローラーでの使用方法
依存性注入を使用してトークンサービスを利用します:
public function logout(Request $request, TokenService $tokenService)
{
if ($tokenService->deleteToken($request->input('api_token'))) {
return response()->json(['success' => true]);
}
return response()->json(['error' => 'ログアウトに失敗しました'], 400);
}
手動でサービスインスタンスを取得する場合:
$user = app(\App\Contracts\TokenService::class)->getUserByToken(
$request->input('api_token')
);
Redisへの切り替え時は、新しい実装クラスを作成しサービスバインディングを変更するだけで、既存コードへの影響はありません。