本文へ移動
Laravel Tips

ミドルウェア

リクエストがアプリに届く前後に間に入って確かめる、ミドルウェアの作り方・登録のしかた・グループ・別名・パラメータ・後始末の処理を説明します。

ミドルウェアは、ブラウザから来たリクエスト(お願い)が、アプリの本体に届く前に通る「関所」のような処理です。リクエストを調べて、通すか、止めるかを決められます。たとえば、Laravel にはログインしているかを確かめるミドルウェアがあります。ログインしていなければログイン画面へ送り、していれば先へ通します。

ほかにも、届いたリクエストをすべて記録するミドルウェアなど、いろいろ作れます。認証(ログインして「だれか」を確かめること)や CSRF 対策のミドルウェアは、Laravel が最初から持っています。自分で作ったミドルウェアは、ふつう app/Http/Middleware フォルダに置きます。

ミドルウェアを作る#

make:middleware という Artisan コマンド(php artisan で動かす Laravel のコマンド)で、ひな形ができます。

bash
php artisan make:middleware EnsureTokenIsValid

app/Http/Middleware に EnsureTokenIsValid クラスができます。次の例は、送られてきた token が決めた値と合うときだけ通し、合わなければ /home へ転送します。

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureTokenIsValid
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->input('token') !== 'my-secret-token') {
            return redirect('/home');
        }

        return $next($request);
    }
}

token が合わなければ、転送のレスポンス(サーバーが返す答え)を返して、そこで止めます。合えば、$next に $request を渡して呼びます。これが、リクエストをアプリのさらに奥へ通す(関所を通す)合図です。

ミドルウェアは、HTTP リクエストが本体に届くまでに通る何枚もの「層」だと考えると分かりやすいです。層ごとにリクエストを調べて、通さないこともできます。

補足

ミドルウェアはサービスコンテナ(クラスを作って渡してくれる道具箱)から作られます。だから、必要な部品は、コンストラクタ(クラスを作るときに動く部分)に型を書けば受け取れます。

リクエストの前と後に処理する#

ミドルウェアは、リクエストを奥へ渡す前にも、渡したあとにも、処理を書けます。次のミドルウェアは、アプリがリクエストを処理する前に仕事をします。

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class BeforeMiddleware
{
    public function handle(Request $request, Closure $next): Response
    {
        // 処理を書く

        return $next($request);
    }
}

こちらは、アプリがリクエストを処理した後に仕事をします。

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

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

        // 処理を書く

        return $response;
    }
}

ミドルウェアを登録する#

作っただけでは動きません。どこに使うかを決めて登録します。

すべてのリクエストにかける(グローバルミドルウェア)#

すべての HTTP リクエストで動かしたいときは、bootstrap/app.php で、全体のミドルウェアの並びに足します。

php
use App\Http\Middleware\EnsureTokenIsValid;

->withMiddleware(function (Middleware $middleware): void {
     $middleware->append(EnsureTokenIsValid::class);
})

withMiddleware のクロージャ(名前のない関数)には、$middleware が渡されます。これは Illuminate\Foundation\Configuration\Middleware クラスの実体で、ルートにかかるミドルウェアをまとめて管理する係です。append は並びの最後に足します。最初に足したいときは prepend を使います。

標準の全体ミドルウェアを自分で管理する#

Laravel が最初から入れている全体のミドルウェアを、自分で管理したいときは、標準の一覧を use メソッドに渡します。そこから、必要に応じて足したり減らしたりします。

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->use([
        \Illuminate\Http\Middleware\ValidatePathEncoding::class,
        \Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class,
        // \Illuminate\Http\Middleware\TrustHosts::class,
        \Illuminate\Http\Middleware\TrustProxies::class,
        \Illuminate\Http\Middleware\HandleCors::class,
        \Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Http\Middleware\ValidatePostSize::class,
        \Illuminate\Foundation\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ]);
})

特定のルートにかける#

一部のルートだけにかけたいときは、ルートに middleware メソッドをつなぎます。

php
use App\Http\Middleware\EnsureTokenIsValid;

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

配列で渡せば、複数かけられます。

php
Route::get('/', function () {
    // ...
})->middleware([First::class, Second::class]);

ミドルウェアを外す#

ルートのグループにミドルウェアをかけたとき、グループの中の1つのルートだけ外したいことがあります。withoutMiddleware を使います。

php
use App\Http\Middleware\EnsureTokenIsValid;

Route::middleware([EnsureTokenIsValid::class])->group(function () {
    Route::get('/', function () {
        // ...
    });

    Route::get('/profile', function () {
        // ...
    })->withoutMiddleware([EnsureTokenIsValid::class]);
});

ルートグループ全体から外すこともできます。

php
use App\Http\Middleware\EnsureTokenIsValid;

Route::withoutMiddleware([EnsureTokenIsValid::class])->group(function () {
    Route::get('/profile', function () {
        // ...
    });
});

補足

withoutMiddleware で外せるのは、ルートにかけたミドルウェアだけです。全体にかけたミドルウェアは外せません。

ミドルウェアのグループ#

いくつかのミドルウェアを、1つの名前でまとめておくと、ルートへ付けるのが楽になります。bootstrap/app.php で appendToGroup を使います。

php
use App\Http\Middleware\First;
use App\Http\Middleware\Second;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->appendToGroup('group-name', [
        First::class,
        Second::class,
    ]);

    $middleware->prependToGroup('group-name', [
        First::class,
        Second::class,
    ]);
})

グループは、1つのミドルウェアと同じ書き方で、ルートやコントローラーに付けられます。

php
Route::get('/', function () {
    // ...
})->middleware('group-name');

Route::middleware(['group-name'])->group(function () {
    // ...
});

最初からあるグループ#

Laravel には、web と api のグループが最初からあります。routes/web.php と routes/api.php のルートには、自動でかかります。

web グループのミドルウェアは次のとおりです。

ミドルウェア 説明
Illuminate\Cookie\Middleware\EncryptCookies Cookie(ブラウザに覚えさせる小さなデータ)を暗号化する
Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse 後で渡す予定の Cookie をレスポンスに付ける
Illuminate\Session\Middleware\StartSession セッションを始める
Illuminate\View\Middleware\ShareErrorsFromSession セッションのエラーをビューで使えるようにする
Illuminate\Foundation\Http\Middleware\PreventRequestForgery CSRF 対策をする
Illuminate\Routing\Middleware\SubstituteBindings URL の値からモデルを取り出す(ルートモデルバインディング)

api グループのミドルウェアは次の1つです。

ミドルウェア 説明
Illuminate\Routing\Middleware\SubstituteBindings URL の値からモデルを取り出す(ルートモデルバインディング)

この2つのグループに足したいときは、bootstrap/app.php の web と api メソッドを使います。appendToGroup の近道です。

php
use App\Http\Middleware\EnsureTokenIsValid;
use App\Http\Middleware\EnsureUserIsSubscribed;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->web(append: [
        EnsureUserIsSubscribed::class,
    ]);

    $middleware->api(prepend: [
        EnsureTokenIsValid::class,
    ]);
})

最初からあるものを、自作のものに差しかえることもできます。

php
use App\Http\Middleware\StartCustomSession;
use Illuminate\Session\Middleware\StartSession;

$middleware->web(replace: [
    StartSession::class => StartCustomSession::class,
]);

まるごと外すこともできます。

php
$middleware->web(remove: [
    StartSession::class,
]);

最初からあるグループを自分で管理する#

web と api の中身を全部自分で管理したいときは、グループを作り直します。次の例は、最初からある中身で作り直したものです。ここから好きに変えられます。

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->group('web', [
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
    ]);

    $middleware->group('api', [
        // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        // 'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ]);
})

補足

web と api のグループは、bootstrap/app.php によって、routes/web.php と routes/api.php に自動でかかります。

別名(エイリアス)を付ける#

長いクラス名のミドルウェアには、短い別名を付けられます。bootstrap/app.php に書きます。

php
use App\Http\Middleware\EnsureUserIsSubscribed;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'subscribed' => EnsureUserIsSubscribed::class
    ]);
})

別名を決めたら、ルートに付けるときに別名で書けます。

php
Route::get('/profile', function () {
    // ...
})->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 署名付き URL(書きかえを見破れる URL)を確かめる(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 メソッドで、優先する順番を決めます。

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->priority([
        \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class,
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ]);
})

いまある優先の一覧を置きかえずに、足すだけにしたいときは、prependToPriorityList と appendToPriorityList を使います。

メソッド 説明
priority 優先する順番の一覧を、まるごと決める
prependToPriorityList 指定したミドルウェアの前に、別のミドルウェアを入れる
appendToPriorityList 指定したミドルウェアの後に、別のミドルウェアを入れる
php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->prependToPriorityList(
        before: \Illuminate\Routing\Middleware\SubstituteBindings::class,
        prepend: \App\Http\Middleware\EnsureTokenIsValid::class,
    );

    $middleware->appendToPriorityList(
        after: \Illuminate\Routing\Middleware\SubstituteBindings::class,
        append: \App\Http\Middleware\EnsureUserIsSubscribed::class,
    );
})

before と after には、ミドルウェアのクラスの配列も渡せます。

ミドルウェアにパラメータを渡す#

ミドルウェアには、追加の値(パラメータ)も渡せます。たとえば、ログイン中の人が、ある「役割(ロール)」を持つかを確かめたいなら、役割の名前を受け取る EnsureUserHasRole ミドルウェアが作れます。

追加の値は、$next のあとの引数で受け取ります。

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, string $role): Response
    {
        if (! $request->user()->hasRole($role)) {
            // 転送などをする
        }

        return $next($request);
    }
}

ルートに付けるときは、ミドルウェアの名前のあとに : を書き、その後ろにパラメータを書きます。

php
use App\Http\Middleware\EnsureUserHasRole;

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

パラメータが複数あるときは、カンマで区切ります。

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

レスポンスを返したあとに動かす(terminate)#

ブラウザへレスポンスを送ったあとに、仕事をしたいことがあります。ミドルウェアに terminate メソッドを書いておくと、Web サーバーが FastCGI(Web サーバーと PHP をつなぐしくみの1つ)を使っているとき、レスポンスを送ったあとに自動で呼ばれます。

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class TerminatingMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        return $next($request);
    }

    /**
     * Handle tasks after the response has been sent to the browser.
     */
    public function terminate(Request $request, Response $response): void
    {
        // ...
    }
}

terminate は、リクエストとレスポンスの両方を受け取ります。作ったら、bootstrap/app.php で、ルートか全体のミドルウェアに足します。

terminate を呼ぶとき、Laravel はサービスコンテナから、新しいミドルウェアのインスタンス(実体)を作ります。handle と terminate で同じインスタンスを使いたいときは、コンテナの singleton メソッド(1つだけ作って使い回す登録のしかた)で登録します。ふつうは AppServiceProvider の register メソッドに書きます。

php
use App\Http\Middleware\TerminatingMiddleware;

/**
 * Register any application services.
 */
public function register(): void
{
    $this->app->singleton(TerminatingMiddleware::class);
}

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧