はじめに

ミドルウェアは、アプリケーションに入るHTTPリクエストを検査し、フィルタリングするための便利なメカニズムを提供します。たとえば、Laravelには、アプリケーションのユーザーが認証されていることを確認するミドルウェアが含まれています。ユーザーが認証されていない場合、ミドルウェアはユーザーをアプリケーションのログイン画面にリダイレクトします。しかし、ユーザーが認証されている場合、ミドルウェアはリクエストをアプリケーション内でさらに進めることを許可します。

追加のミドルウェアは、認証以外のさまざまなタスクを実行するために作成できます。たとえば、ロギングミドルウェアは、アプリケーションに入るすべてのリクエストをログに記録するかもしれません。Laravelには、認証やCSRF保護のためのミドルウェアを含むさまざまなミドルウェアが含まれていますが、すべてのユーザー定義のミドルウェアは通常、アプリケーションのapp/Http/Middlewareディレクトリにあります。

ミドルウェアの定義

新しいミドルウェアを作成するには、make:middleware Artisanコマンドを使用します:

  1. php artisan make:middleware EnsureTokenIsValid

このコマンドは、app/Http/Middlewareディレクトリ内に新しいEnsureTokenIsValidクラスを配置します。このミドルウェアでは、提供されたtoken入力が指定された値と一致する場合にのみ、ルートへのアクセスを許可します。そうでない場合、ユーザーを/home URIにリダイレクトします:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. class EnsureTokenIsValid
  7. {
  8. /**
  9. * Handle an incoming request.
  10. *
  11. * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
  12. */
  13. public function handle(Request $request, Closure $next): Response
  14. {
  15. if ($request->input('token') !== 'my-secret-token') {
  16. return redirect('/home');
  17. }
  18. return $next($request);
  19. }
  20. }

ご覧のとおり、指定されたtokenが秘密のトークンと一致しない場合、ミドルウェアはクライアントにHTTPリダイレクトを返します。そうでない場合、リクエストはアプリケーション内でさらに進められます。リクエストをアプリケーション内でさらに進めるには(ミドルウェアに「通過」させるために)、$nextコールバックを$requestで呼び出す必要があります。

ミドルウェアは、HTTPリクエストがアプリケーションに到達する前に通過しなければならない一連の「レイヤー」として考えるのが最適です。各レイヤーはリクエストを検査し、完全に拒否することさえできます。

すべてのミドルウェアはサービスコンテナを介して解決されるため、ミドルウェアのコンストラクタ内で必要な依存関係を型ヒントすることができます。

ミドルウェアとレスポンス

もちろん、ミドルウェアはリクエストをアプリケーション内でさらに進める前または後にタスクを実行できます。たとえば、次のミドルウェアは、リクエストがアプリケーションによって処理されるにいくつかのタスクを実行します:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. class BeforeMiddleware
  7. {
  8. public function handle(Request $request, Closure $next): Response
  9. {
  10. // Perform action
  11. return $next($request);
  12. }
  13. }

しかし、このミドルウェアは、リクエストがアプリケーションによって処理されたにタスクを実行します:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. class AfterMiddleware
  7. {
  8. public function handle(Request $request, Closure $next): Response
  9. {
  10. $response = $next($request);
  11. // Perform action
  12. return $response;
  13. }
  14. }

ミドルウェアの登録

グローバルミドルウェア

アプリケーションへのすべてのHTTPリクエスト中にミドルウェアを実行したい場合は、アプリケーションのbootstrap/app.phpファイルのグローバルミドルウェアスタックに追加できます:

  1. use App\Http\Middleware\EnsureTokenIsValid;
  2. ->withMiddleware(function (Middleware $middleware) {
  3. $middleware->append(EnsureTokenIsValid::class);
  4. })
  1. <a name="manually-managing-laravels-default-global-middleware"></a>
  2. #### Laravelのデフォルトグローバルミドルウェアの手動管理
  3. Laravelのグローバルミドルウェアスタックを手動で管理したい場合は、Laravelのデフォルトのグローバルミドルウェアスタックを`````use`````メソッドに提供できます。その後、必要に応じてデフォルトのミドルウェアスタックを調整できます:
  4. ``````php
  5. ->withMiddleware(function (Middleware $middleware) {
  6. $middleware->use([
  7. // \Illuminate\Http\Middleware\TrustHosts::class,
  8. \Illuminate\Http\Middleware\TrustProxies::class,
  9. \Illuminate\Http\Middleware\HandleCors::class,
  10. \Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
  11. \Illuminate\Http\Middleware\ValidatePostSize::class,
  12. \Illuminate\Foundation\Http\Middleware\TrimStrings::class,
  13. \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
  14. ]);
  15. })
  16. `

ルートへのミドルウェアの割り当て

特定のルートにミドルウェアを割り当てたい場合は、ルートを定義するときにmiddlewareメソッドを呼び出すことができます:

  1. use App\Http\Middleware\EnsureTokenIsValid;
  2. Route::get('/profile', function () {
  3. // ...
  4. })->middleware(EnsureTokenIsValid::class);
  1. ``````php
  2. Route::get('/', function () {
  3. // ...
  4. })->middleware([First::class, Second::class]);
  5. `

ミドルウェアの除外

ルートのグループにミドルウェアを割り当てるとき、グループ内の個々のルートにミドルウェアが適用されないようにする必要がある場合があります。これは、withoutMiddlewareメソッドを使用して達成できます:

  1. use App\Http\Middleware\EnsureTokenIsValid;
  2. Route::middleware([EnsureTokenIsValid::class])->group(function () {
  3. Route::get('/', function () {
  4. // ...
  5. });
  6. Route::get('/profile', function () {
  7. // ...
  8. })->withoutMiddleware([EnsureTokenIsValid::class]);
  9. });

特定のミドルウェアセットをルート定義の全体のグループから除外することもできます:

  1. use App\Http\Middleware\EnsureTokenIsValid;
  2. Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
  3. Route::get('/profile', function () {
  4. // ...
  5. });
  6. });
  1. <a name="middleware-groups"></a>
  2. ### ミドルウェアグループ
  3. 時には、複数のミドルウェアを単一のキーの下にグループ化して、ルートに割り当てやすくしたい場合があります。これは、アプリケーションの`````bootstrap/app.php`````ファイル内で`````appendToGroup`````メソッドを使用して達成できます:
  4. ``````php
  5. use App\Http\Middleware\First;
  6. use App\Http\Middleware\Second;
  7. ->withMiddleware(function (Middleware $middleware) {
  8. $middleware->appendToGroup('group-name', [
  9. First::class,
  10. Second::class,
  11. ]);
  12. $middleware->prependToGroup('group-name', [
  13. First::class,
  14. Second::class,
  15. ]);
  16. })
  17. `

ミドルウェアグループは、個々のミドルウェアと同じ構文を使用してルートやコントローラーアクションに割り当てることができます:

  1. Route::get('/', function () {
  2. // ...
  3. })->middleware('group-name');
  4. Route::middleware(['group-name'])->group(function () {
  5. // ...
  6. });

Laravelのデフォルトミドルウェアグループ

Laravelには、WebおよびAPIルートに適用したい一般的なミドルウェアを含む、あらかじめ定義されたwebおよびapiミドルウェアグループが含まれています。Laravelは、これらのミドルウェアグループを対応するroutes/web.phpおよびroutes/api.phpファイルに自動的に適用します:

web ミドルウェアグループ
Illuminate\Cookie\Middleware\EncryptCookies
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse
Illuminate\Session\Middleware\StartSession
Illuminate\View\Middleware\ShareErrorsFromSession
Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
Illuminate\Routing\Middleware\SubstituteBindings
api ミドルウェアグループ
Illuminate\Routing\Middleware\SubstituteBindings

これらのグループにミドルウェアを追加または先頭に追加したい場合は、アプリケーションのbootstrap/app.phpファイル内でwebおよびapiメソッドを使用できます。webおよびapiメソッドは、appendToGroupメソッドの便利な代替手段です:

  1. use App\Http\Middleware\EnsureTokenIsValid;
  2. use App\Http\Middleware\EnsureUserIsSubscribed;
  3. ->withMiddleware(function (Middleware $middleware) {
  4. $middleware->web(append: [
  5. EnsureUserIsSubscribed::class,
  6. ]);
  7. $middleware->api(prepend: [
  8. EnsureTokenIsValid::class,
  9. ]);
  10. })

Laravelのデフォルトミドルウェアグループのエントリの1つをカスタムミドルウェアに置き換えることもできます:

  1. use App\Http\Middleware\StartCustomSession;
  2. use Illuminate\Session\Middleware\StartSession;
  3. $middleware->web(replace: [
  4. StartSession::class => StartCustomSession::class,
  5. ]);

または、ミドルウェアを完全に削除することもできます:

  1. $middleware->web(remove: [
  2. StartSession::class,
  3. ]);

Laravelのデフォルトミドルウェアグループの手動管理

Laravelのデフォルトwebおよびapiミドルウェアグループ内のすべてのミドルウェアを手動で管理したい場合は、グループを完全に再定義できます。以下の例では、webおよびapiミドルウェアグループをデフォルトのミドルウェアで定義し、必要に応じてカスタマイズできるようにします:

  1. ->withMiddleware(function (Middleware $middleware) {
  2. $middleware->group('web', [
  3. \Illuminate\Cookie\Middleware\EncryptCookies::class,
  4. \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
  5. \Illuminate\Session\Middleware\StartSession::class,
  6. \Illuminate\View\Middleware\ShareErrorsFromSession::class,
  7. \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
  8. \Illuminate\Routing\Middleware\SubstituteBindings::class,
  9. // \Illuminate\Session\Middleware\AuthenticateSession::class,
  10. ]);
  11. $middleware->group('api', [
  12. // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
  13. // 'throttle:api',
  14. \Illuminate\Routing\Middleware\SubstituteBindings::class,
  15. ]);
  16. })

デフォルトでは、webおよびapiミドルウェアグループは、bootstrap/app.phpファイルによってアプリケーションの対応するroutes/web.phpおよびroutes/api.phpファイルに自動的に適用されます。

ミドルウェアエイリアス

アプリケーションのbootstrap/app.phpファイル内でミドルウェアにエイリアスを割り当てることができます。ミドルウェアエイリアスを使用すると、特定のミドルウェアクラスの短いエイリアスを定義でき、特に長いクラス名のミドルウェアに便利です:

  1. use App\Http\Middleware\EnsureUserIsSubscribed;
  2. ->withMiddleware(function (Middleware $middleware) {
  3. $middleware->alias([
  4. 'subscribed' => EnsureUserIsSubscribed::class
  5. ]);
  6. })

アプリケーションのbootstrap/app.phpファイルでミドルウェアエイリアスが定義されると、ルートにミドルウェアを割り当てるときにエイリアスを使用できます:

  1. Route::get('/profile', function () {
  2. // ...
  3. })->middleware('subscribed');

便利なことに、Laravelの組み込みミドルウェアのいくつかはデフォルトでエイリアスが付けられています。たとえば、authミドルウェアはIlluminate\Auth\Middleware\Authenticateミドルウェアのエイリアスです。以下はデフォルトのミドルウェアエイリアスのリストです:

エイリアス ミドルウェア
auth Illuminate\Auth\Middleware\Authenticate
auth.basic Illuminate\Auth\Middleware\AuthenticateWithBasicAuth
auth.session Illuminate\Session\Middleware\AuthenticateSession
cache.headers Illuminate\Http\Middleware\SetCacheHeaders
can Illuminate\Auth\Middleware\Authorize
guest Illuminate\Auth\Middleware\RedirectIfAuthenticated
password.confirm Illuminate\Auth\Middleware\RequirePassword
precognitive Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests
signed Illuminate\Routing\Middleware\ValidateSignature
subscribed \Spark\Http\Middleware\VerifyBillableIsSubscribed
throttle Illuminate\Routing\Middleware\ThrottleRequests または Illuminate\Routing\Middleware\ThrottleRequestsWithRedis
verified Illuminate\Auth\Middleware\EnsureEmailIsVerified

ミドルウェアのソート

まれに、ミドルウェアを特定の順序で実行する必要がありますが、ルートに割り当てるときにその順序を制御できない場合があります。このような状況では、アプリケーションのbootstrap/app.phpファイル内でpriorityメソッドを使用してミドルウェアの優先順位を指定できます:

  1. ->withMiddleware(function (Middleware $middleware) {
  2. $middleware->priority([
  3. \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
  4. \Illuminate\Cookie\Middleware\EncryptCookies::class,
  5. \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
  6. \Illuminate\Session\Middleware\StartSession::class,
  7. \Illuminate\View\Middleware\ShareErrorsFromSession::class,
  8. \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
  9. \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
  10. \Illuminate\Routing\Middleware\ThrottleRequests::class,
  11. \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
  12. \Illuminate\Routing\Middleware\SubstituteBindings::class,
  13. \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
  14. \Illuminate\Auth\Middleware\Authorize::class,
  15. ]);
  16. })

ミドルウェアパラメータ

ミドルウェアは追加のパラメータを受け取ることもできます。たとえば、アプリケーションが認証されたユーザーが特定のアクションを実行する前に特定の「役割」を確認する必要がある場合、役割名を追加の引数として受け取るEnsureUserHasRoleミドルウェアを作成できます。

追加のミドルウェアパラメータは、$next引数の後にミドルウェアに渡されます:

  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. class EnsureUserHasRole
  7. {
  8. /**
  9. * Handle an incoming request.
  10. *
  11. * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
  12. */
  13. public function handle(Request $request, Closure $next, string $role): Response
  14. {
  15. if (! $request->user()->hasRole($role)) {
  16. // Redirect...
  17. }
  18. return $next($request);
  19. }
  20. }

ミドルウェアパラメータは、ルートを定義するときにミドルウェア名とパラメータを:で区切ることで指定できます:

  1. use App\Http\Middleware\EnsureUserHasRole;
  2. Route::put('/post/{id}', function (string $id) {
  3. // ...
  4. })->middleware(EnsureUserHasRole::class.':editor');

複数のパラメータはカンマで区切ることができます:

  1. Route::put('/post/{id}', function (string $id) {
  2. // ...
  3. })->middleware(EnsureUserHasRole::class.':editor,publisher');

終了可能なミドルウェア

時には、ミドルウェアがHTTPレスポンスがブラウザに送信された後に作業を行う必要がある場合があります。ミドルウェアにterminateメソッドを定義し、WebサーバーがFastCGIを使用している場合、レスポンスがブラウザに送信された後にterminateメソッドが自動的に呼び出されます:

  1. <?php
  2. namespace Illuminate\Session\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. class TerminatingMiddleware
  7. {
  8. /**
  9. * Handle an incoming request.
  10. *
  11. * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
  12. */
  13. public function handle(Request $request, Closure $next): Response
  14. {
  15. return $next($request);
  16. }
  17. /**
  18. * Handle tasks after the response has been sent to the browser.
  19. */
  20. public function terminate(Request $request, Response $response): void
  21. {
  22. // ...
  23. }
  24. }
  1. `````terminate`````メソッドをミドルウェアで呼び出すと、Laravelは[サービスコンテナ](/read/laravel-11-x/89c648800d1f2464.md)からミドルウェアの新しいインスタンスを解決します。`````handle`````および`````terminate`````メソッドが呼び出されるときに同じミドルウェアインスタンスを使用したい場合は、コンテナの`````singleton`````メソッドを使用してミドルウェアをコンテナに登録します。通常、これは`````register`````メソッドの中で行うべきです:
  2. ``````php
  3. use App\Http\Middleware\TerminatingMiddleware;
  4. /**
  5. * Register any application services.
  6. */
  7. public function register(): void
  8. {
  9. $this->app->singleton(TerminatingMiddleware::class);
  10. }
  11. `