【Laravel】Middlewareを深堀りして解説

laravelアイキャッチ Laravel

こんにちは、かつコーチです。

LaravelのMiddlewareについては解説しましたが、もう少し理解を深めるために、

今回は、より深堀りして解説します。

前半は、よく利用するAuthenticateとRedirectIfAuthenticatedについて解説し、

後半は、それ以外について解説します。

AuthenticateとRedirectIfAuthenticated

Authenticate ミドルウェアの役割

Authenticate ミドルウェアは、特定のルートにアクセスする前に認証を確認する役割を持っています。

ユーザーが認証されていない場合、このミドルウェアが作動し、

ユーザーをログインページにリダイレクトします。

通常、デフォルトでは Laravel の Authenticate.php は単一のリダイレクト先(/loginなど)を指定しますが、

マルチログイン(管理者、従業員、所有者、一般ユーザー)を扱うことも可能で、

それぞれのログイン画面に適切にリダイレクトすると実現できます。

マルチログインのカスタマイズした例

class Authenticate extends Middleware
{
    protected $user_route = 'user.login';
    protected $admin_route = 'admin.login';
    protected $employee_route = 'employee.login';
    protected $owner_route = 'owner.login';

    protected function redirectTo($request)
    {
        if (! $request->expectsJson()) {
            if (Route::is('owner.*')) {
                return route($this->owner_route);
            } elseif (Route::is('admin.*')) {
                return route($this->admin_route);
            } elseif (Route::is('employee.*')) {
                return route($this->employee_route);
            } else {
                return route($this->user_route);
            }
        }
    }
}

詳細な解説:

  1. ルートに基づいた分岐:
    • Route::is() メソッドを使用して、リクエストされたルートが owner.*admin.*employee.*、もしくはデフォルトの user ルートのいずれかであるかを確認しています。
    • route() メソッドを使用して、それぞれのルートにリダイレクトします。これにより、各種ログイン画面(管理者、従業員、所有者、一般ユーザー)の分岐が可能になります。
  2. $request->expectsJson() の役割:
    • APIリクエストなどの際に、クライアントがJSONレスポンスを期待している場合、ログインページへのリダイレクトではなく、適切なエラーレスポンス(例: 401 Unauthorized)を返す必要があります。このため、expectsJson() をチェックして、APIリクエストであればリダイレクトせずにエラーレスポンスを返すようにしています。

RedirectIfAuthenticated ミドルウェアの役割

RedirectIfAuthenticated は、認証済みのユーザーが再びログイン画面にアクセスしようとした場合に、

ログイン画面ではなくダッシュボードなどのホーム画面にリダイレクトする役割を持っています。

マルチログインのカスタマイズした例

class RedirectIfAuthenticated
{
    private const GUARD_USER = 'users';
    private const GUARD_ADMIN = 'admins';
    private const GUARD_EMPLOYEE = 'employees';
    private const GUARD_OWNER = 'owners';

    public function handle(Request $request, Closure $next, ...$guards)
    {
        if (Auth::guard(self::GUARD_USER)->check() && $request->routeIs('user.*')) {
            return redirect(RouteServiceProvider::HOME);
        }

        if(Auth::guard(self::GUARD_ADMIN)->check() && $request->routeIs('admin.*')) {
            return redirect(RouteServiceProvider::ADMIN_HOME);
        }

        if(Auth::guard(self::GUARD_EMPLOYEE)->check() && $request->routeIs('employee.*')) {
            return redirect(RouteServiceProvider::EMPLOYEE_HOME);
        }

        if(Auth::guard(self::GUARD_OWNER)->check() && $request->routeIs('owner.*')) {
            return redirect(RouteServiceProvider::OWNER_HOME);
        }

        return $next($request);
    }
}

詳細な解説:

  1. マルチガードによる認証状態のチェック:
    • Auth::guard() を使用して、それぞれのユーザータイプ(ユーザー、管理者、従業員、所有者)ごとの認証状態を確認しています。
    • それぞれのユーザーがログイン済みかつ特定のルートにアクセスしている場合、該当するホーム画面にリダイレクトします。
  2. $request->routeIs() の役割:
    • routeIs() メソッドを使って、現在のリクエストが特定の名前付きルートにマッチするかを確認しています。これにより、ログイン済みのユーザーが再度ログイン画面にアクセスしたときに、自動的に対応するホームページにリダイレクトされるようになっています。
  3. $next($request) の役割:
    • 認証が行われていない場合、リクエストを次のミドルウェアに渡して、通常のルート処理が進むようにします。認証されていないユーザーはログインページにアクセスできます。

マルチログインの実装での考慮点

  • 認証ガードの使用:
    • Laravel の認証システムでは、デフォルトで webapi のガードがありますが、マルチログインを実現するためには、新しいガード(例: admins, employees, owners)を設定し、それぞれのガードに対応する認証ドライバーやモデルを設定する必要があります。これらは config/auth.php で設定します。
  • RouteServiceProvider の使用:
    • ルートのリダイレクト先は RouteServiceProvider で定義されることが多く、ユーザーの種類に応じたホーム画面にリダイレクトできるように、各ホームページの定義をカスタマイズします。例えば、RouteServiceProvider::HOMERouteServiceProvider::ADMIN_HOME などを用意しておくと、リダイレクト先を簡単に管理できます。

その他のMiddleware

Laravelには、EncryptCookies, TrimStrings, VerifyCsrfToken など、

多くのミドルウェアがデフォルトで提供されています。

これらのミドルウェアはそれぞれ異なる役割を果たしており、

通常のWebアプリケーション開発でのセキュリティやパフォーマンスの向上に貢献しています。

これらを深掘りし、どのようなときに触れるかや、カスタマイズの可能性について詳しく説明します。

EncryptCookies (app/Http/Middleware/EncryptCookies.php)

役割:

EncryptCookies ミドルウェアは、アプリケーションでクッキーに保存されるデータを自動的に暗号化し、

かつ解読する役割を持っています。

Laravelは、セキュリティ上、クッキー内のデータを暗号化することを推奨しており、

このミドルウェアを通してそれが実現されています。

特徴:

  • クッキーに保存されるデータを暗号化し、第三者がクッキーの内容を簡単に読み取れないように保護します。
  • クッキーのデータは次回のリクエスト時に自動で解読されるため、開発者が暗号化・解読処理を意識する必要はありません。

どのようなときに触れるか:

通常、クッキー操作をする際に、EncryptCookiesに意識的に触れることはあまりありませんが、特定のクッキーを暗号化したくない場合は、EncryptCookies$except プロパティにそのクッキー名を追加することで、除外できます。

protected $except = [
    'cookie_name_to_exclude'
];

カスタマイズの例:

例えば、認証やセッション管理に関係ない一部のクッキーを暗号化しないようにしたい場合などに、除外リストを利用できます。


TrimStrings (app/Http/Middleware/TrimStrings.php)

役割:

TrimStrings ミドルウェアは、すべての入力文字列の先頭と末尾の空白を

自動的に取り除く役割を持っています。

これにより、ユーザーがフォームに入力した際に不要な空白が含まれる問題を防ぐことができます。

特徴:

  • フォーム入力などでの意図しない空白を防ぎ、データの一貫性を保つ。
  • ユーザー入力を扱う際に、余分な空白を取り除くことで、意図しない動作やバリデーションエラーを防ぎます。

どのようなときに触れるか:

通常は自動で処理されるため、意識的に触れることはあまりありません。

ただし、特定のフィールドで空白をそのまま保存したい場合は、

除外するフィールドを $except プロパティに指定します。

protected $except = [
    'description', // 例えば、説明フィールドなどで空白を残す
];

VerifyCsrfToken (app/Http/Middleware/VerifyCsrfToken.php)

役割:

VerifyCsrfToken ミドルウェアは、CSRF(Cross-Site Request Forgery)攻撃を防ぐためのものです。

CSRFトークンは、フォームやリクエストに付与される秘密のトークンで、

正当なリクエストかどうかを検証します。

特徴:

  • フォーム送信時に、@csrf ディレクティブや <meta name="csrf-token"> を使用してトークンを生成・送信し、そのトークンが正しいかどうかをこのミドルウェアで検証します。
  • CSRFトークンが一致しないリクエストは、403 Forbidden エラーが発生し、リクエストが拒否されます。

どのようなときに触れるか:

通常は、フォームや非同期リクエスト(Ajax)を処理する際に自動的に機能します。

@csrf ディレクティブを使用することでフォームにトークンを追加し、

meta タグでJavaScriptが使用するCSRFトークンを埋め込みます。

<meta name="csrf-token" content="{{ csrf_token() }}">

カスタマイズの可能性:

特定のURLやAPIエンドポイントでCSRFトークンの検証を除外したい場合、

VerifyCsrfToken ミドルウェアの $except プロパティにURLを指定できます。

protected $except = [
    'api/*', // APIは一般的にCSRFトークンの検証を行わないことが多い
];
  • 特定のリクエストでCSRFトークンをバイパスしたり、特定のトークンやヘッダーの形式を調整したい場合にこのミドルウェアをカスタマイズできます。

その他のミドルウェア

Laravelには他にも多くのミドルウェアが存在し、それぞれ異なる役割を持っています。

いくつかの例を挙げて深掘りします。

HandleCors

  • 役割: CORS(Cross-Origin Resource Sharing)ポリシーを設定します。APIを公開する際や、他のオリジン(ドメイン)からのリクエストを受け入れるかどうかを制御します。
  • カスタマイズ: config/cors.php で許可するオリジン、メソッド、ヘッダーなどを設定できます。

CheckForMaintenanceMode

  • 役割: アプリケーションがメンテナンスモード中(php artisan down コマンドで有効)である場合に、ユーザーに503エラーページを表示します。
  • カスタマイズ: メンテナンスモード中にアクセスを許可したい特定のIPアドレスを whitelist に設定できます。

SetLocale

  • 役割: アプリケーションの言語をリクエストごとに変更します。通常、URLやリクエストヘッダーで言語を指定する場合に使用します。

まとめ

  • Authenticate ミドルウェア: 認証されていないユーザーがアクセスした場合にログインページにリダイレクトします。マルチログインの際には、各ユーザータイプごとのログインページにリダイレクトするためのカスタマイズが必要です。
  • RedirectIfAuthenticated ミドルウェア: すでに認証されているユーザーがログインページにアクセスしようとした場合、適切なホームページにリダイレクトします。ここでもマルチログインに対応するため、ユーザーごとのリダイレクト先を設定します。
  • EncryptCookies: クッキーのセキュリティ保護のために暗号化を行う。除外リストを使って特定のクッキーの暗号化を無効にすることも可能。
  • TrimStrings: フォームデータの前後の空白を自動的に取り除く。特定のフィールドを除外することも可能。
  • VerifyCsrfToken: CSRF攻撃を防ぐためにトークンの検証を行う。特定のURLやAPIでCSRFトークンの検証を除外することができる。

通常、これらのミドルウェアはLaravelが自動で設定しており、

開発者が明示的に触れることは少ないですが、特定のケースではカスタマイズすることができます。

特に、APIや外部サービスとのやり取りが発生する場合や、

CSRFの制約を調整したい場合にカスタマイズが必要になります。

これらのカスタマイズにより、複数の異なるユーザータイプに対して、

それぞれに応じたログイン、リダイレクトの処理が可能になります。

タイトルとURLをコピーしました