Laravel 6.x ミドルウェア

イントロダクション

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

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

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

ミドルウェア定義

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

php artisan make:middleware CheckAge

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

<?php

namespace App\Http\Middleware;

use Closure;

class CheckAge
{
    /**
     * 送信されてきたリクエストの処理
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->age <= 200) {
            return redirect('home');
        }

        return $next($request);
    }
}

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

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

Tip!! すべてのミドルウェアは、サービスコンテナにより、依存解決されます。そのため、ミドルウェアのコンストラクタに、必要な依存をタイプヒントで指定できます。

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,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];

HTTPカーネルへミドルウェアを定義し終えたら、ルートに対しミドルウェアを指定する、middlewareメソッドを使ってください。

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

ルートに複数のミドルウェアを定義することもできます。

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

ミドルウェアを指定する時に、完全なクラス名を指定することもできます。

use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
    //
})->middleware(CheckAge::class);

ミドルウェアグループ

多くのミドルウェアを一つのキーによりまとめ、ルートへ簡単に指定できるようにしたくなることもあります。HTTPカーネルの$middlewareGroupsプロパティにより可能です。

WebのUIとAPIルートへ適用できる、一般的なミドルウェアを含んだ、webapiミドルウェアグループをLaravelは最初から用意しています。

/**
 * アプリケーションのミドルウェアグループ
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];

ミドルウェアグループは、個別のミドルウェアと同じ記法を使い、ルートやコントローラへ結合します。再度説明しますと、ミドルウェアグループは一度に多くのミドルウエアを簡単に、より便利に割り付けるための方法です。

Route::get('/', function () {
    //
})->middleware('web');

Route::group(['middleware' => ['web']], function () {
    //
});

Route::middleware(['web', 'subscribed'])->group(function () {
    //
});

Tip!! RouteServiceProviderにより、routes/web.phpファイルでは、webミドルウェアグループが自動的に適用されます。

ミドルウェアの優先付け

まれに、特定の順番でミドルウェアを実行する必要が起き得ますが、ルートへミドルウェアを指定する時に順番をコントロールできません。このような場合、app/Http/Kernel.phpファイルの$middlewarePriorityプロパティを使用し、ミドルウェアの優先度を指定できます。

/**
 * ミドルウェアの優先順リスト
 *
 * グローバルではないミドルウェアを常に指定順に強要する
 *
 * @var array
 */
protected $middlewarePriority = [
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];

ミドルウェアパラメータ

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

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

<?php

namespace App\Http\Middleware;

use Closure;

class CheckRole
{
    /**
     * リクエストフィルターを実行
     *
     * @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}', function ($id) {
    //
})->middleware('role:editor');

終了処理ミドルウェア

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

<?php

namespace Illuminate\Session\Middleware;

use Closure;

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

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

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

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

use App\Http\Middleware\TerminableMiddleware;

/**
 * 全アプリケーションサービスの登録
 *
 * @return void
 */
public function register()
{
    $this->app->singleton(TerminableMiddleware::class);
}

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる