Lumenフレームワークにおける依存性注入のカスタマイズ実装

トークン認証システムの実装と切り替え

トークン認証システムを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への切り替え時は、新しい実装クラスを作成しサービスバインディングを変更するだけで、既存コードへの影響はありません。

タグ: Lumen Dependency Injection Service Container PHP Interface Implementation

9月16日 07:30 投稿