イントロダクション
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);
}
}
ご覧の通り、age
が200
以下の場合、ミドルウェアはHTTPリダイレクトをクライアントへ返します。そうでなければ、リクエストはパスし、アプリケーションの先へ進めます。ミドルウェアのチェックに合格し、アプリケーションの先へリクエストを通すには、$request
を渡し$next
コールバックを呼び出すだけです。
ミドルウェアを把握する一番良い方法は、HTTPリクエストがアプリケーションに届くまでに通過する、数々の「レイヤー(層)」なのだと考えることです。それぞれのレイヤーは、リクエストを通過させるかどうかテストし、場合により完全に破棄することさえできます。
Before/Afterミドルウェア
ミドルウェアがリクエストの前、後に実行されるかは、そのミドルウェアの組み方により決まります。次のミドルウェアはアプリケーションによりリクエストが処理される前に実行されます。
<?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はサービスコンテナから真新しいミドルウェアのインスタンスを依存解決します。handle
とterminate
メソッドの呼び出しで同一のミドルウェアインスタンスを使用したい場合は、コンテナのsingleton
メソッドを使用し、ミドルウェアを登録してください。