イントロダクション

HTTPミドルウェアはアプリケーションにやってきたHTTPリクエストをフィルタリングする、便利なメカニズムを提供します。例えば、アプリケーションのユーザーが認証されているかを確認するミドルウェアがLaravelに用意されています。ユーザーが認証されていなければ、このミドルウェアはユーザーをログインページへリダイレクトします。反対にそのユーザーが認証済みであれば、そのリクエストがアプリケーションのその先へ進むことを許可します。

もちろん認証の他にも多彩なタスクを実行するミドルウェアを書くことができます。たとえばCORSミドルウェアは、アプリケーションから返されるレスポンス全部に正しいヘッダーを追加することに責任を持つでしょう。ログミドルウェアはアプリケーションにやってきたリクエスト全部をログすることに責任を負うでしょう。

サイトメンテナンスモードや認証、CSRF保護などLaravelには多くのミドルウェアが用意されています。これらのミドルウェアは全部、app/Http/Middlewareディレクトリーに設置されています。

ミドルウェア定義

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

php artisan make:middleware OldMiddleware

このコマンドにより、OldMiddlewareクラスが、app/Http/Middlewareディレクトリー中に生成されます。このミドルウェアで、ageに200歳以上が指定された場合のみ、アクセスを許してみましょう。そうでなければ、ユーザーを"home"のURIへリダイレクトします。

<?php

namespace App\Http\Middleware;

use Closure;

class OldMiddleware
{
    /**
     * リクエストフィルターを実行
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->input('age') <= 200) {
            return redirect('home');
        }

        return $next($request);
    }

}

ご覧の通り、age200以下の場合、ミドルウェアはHTTPリダイレクトをクライアントへ返します。そうでなければ、リクエストはパスし、アプリケーションの先へ進めます。ミドルウェアのチェックに合格し、アプリケーションの先へリクエストを通すには、$requestを渡し$nextコールバックを呼び出すだけです。

ミドルウェアを把握する一番良い方法は、HTTPリクエストがアプリケーションに届くまでに通過する、数々の「レイヤー(層)」なのだと考えることです。それぞれのレイヤーは、リクエストを通過させるかどうかテストし、場合により完全に破棄することさえできます。

BeforeAfterミドルウェア

ミドルウェアがリクエストの前、後に実行されるかは、そのミドルウェアの組み方により決まります。次のミドルウェアはアプリケーションによりリクエストが処理されるに実行されます。

<?php

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
    public function handle($request, Closure $next)
    {
        // アクションを取るコードをここに記述

        return $next($request);
    }
}

一方、次のミドルウェアはアプリケーションによりリクエストが処理されたにタスクを実行します。

<?php

namespace App\Http\Middleware;

use Closure;

class AfterMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        // アクションを取るコードをここに記述

        return $response;
    }
}

ミドルウェア登録

グローバルミドルウェア

あるミドルウェアをアプリケーションの全HTTPリクエストで実行したい場合は、app/Http/Kernel.phpクラスの$middlewareプロパティへ追加してください。

ミドルウェアをルートへ登録

全ルートに適用するのではなく、特定のルートのみに対しミドルウェアを指定したい場合は、先ずapp/Http/Kernel.phpファイルでミドルウェアの短縮キーを登録します。デフォルト状態でこのクラスは、Laravelに含まれているミドルウェアのエントリーを$routeMiddlewareプロパティに持っています。ミドルウェアを追加する方法は、選んだキー名と一緒にリストへ付け加えるだけです。

//  App\Http\Kernelクラスの中…

protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
];

HTTPカーネルへミドルウェアを定義し終えたら、そのmiddlewareキーをルートのオプション配列で指定できます。

Route::get('admin/profile', ['middleware' => 'auth', function () {
    //
}]);

ルートに複数のミドルウェアを定義するために配列が使えます。

Route::get('/', ['middleware' => ['first', 'second'], function () {
    //
}]);

配列を使う代わりに、ルート定義にmiddlewareメソッドをチェーンすることもできます。

Route::get('/', function () {
    //
})->middleware(['first', 'second']);

ミドルウェアパラメーター

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

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

<?php

namespace App\Http\Middleware;

use Closure;

class RoleMiddleware
{
    /**
     * リクエストフィルターを実行
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role
     * @return mixed
     */
    public function handle($request, Closure $next, $role)
    {
        if (! $request->user()->hasRole($role)) {
            // どこかへのリダイレクト処理…
        }

        return $next($request);
    }

}

ミドルウェアパラメーターはルート定義時に指定され、ミドルウェア名とパラメーターを:で区切ります。複数のパラメーターはカンマで区切ります。

Route::put('post/{id}', ['middleware' => 'role:editor', function ($id) {
    //
}]);

終了処理ミドルウェア

まれにHTTPレスポンスがブラウザに送られた後に、ミドルウェアが何かの作業を行う必要があることもあります。たとえば、Laravelに含まれている「セッション」ミドルウェアは、ブラウザにレスポンスを送ったにストレージへセッションデーターを書き込みます。これをお行うにはterminateメソッドを追加し、終了処理可能な(terminable)としてミドルウェアを定義してください。

<?php

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // セッションデーターの保存
    }
}

terminateメソッドはリクエストとレスポンスの両方を受け取ります。終了処理可能なミドルウェアを定義したら、HTTPカーネルでグローバルミドルウェアのリストへ追加してください。

ミドルウェアのterminateメソッド呼び出し時に、Laravelはサービスコンテナから真新しいミドルウェアのインスタンスを依存解決します。handleterminateメソッドの呼び出しで同一のミドルウェアインスタンスを使用したい場合は、コンテナのsingletonメソッドを使用し、ミドルウェアを登録してください。