【Laravel 11/Middleware】実用的なカスタムミドルウェアの作成と活用例

Laravel 11.x では、ミドルウェアの登録が従来の `app/Http/Kernel.php` ではなく、**`bootstrap/app.php`** に記述されるようになりました。  
また、サービスプロバイダも `artisan make:provider` コマンドで生成すると、自動的に **`bootstrap/providers.php`** に登録されるようになっています。  
ここでは、実際の開発現場で役立つカスタムミドルウェアのサンプルコードを充実させて解説します。

---

## 1. カスタムミドルウェアの基本と実用例

まずは、ユーザーが利用停止（banned）状態の場合に、ログイン後の画面へアクセスさせず、専用の通知ページへリダイレクトするミドルウェアのサンプルを見ていきます。

### 1-1. 利用停止ユーザーのチェックミドルウェア（CheckUserStatus）

**作成コマンド:**

```bash
php artisan make:middleware CheckUserStatus
```

**生成されるファイル:**  
`app/Http/Middleware/CheckUserStatus.php`

**サンプルコード:**

```php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class CheckUserStatus
{
    /**
     * Handle an incoming request.
     *
     * ユーザーが利用停止状態の場合、専用の通知ページへリダイレクトする
     *
     * @param  \Illuminate\Http\Request  $request  現在の HTTP リクエスト
     * @param  \Closure  $next  次に実行すべき処理
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // リクエスト前の処理
        $user = Auth::user();

        // ログイン済みかつ利用停止状態の場合（例として、Userモデルに isBanned() メソッドがある）
        if ($user && $user->isBanned()) {
            // 利用停止の通知ページへリダイレクト
            return redirect()->route('banned.notice');
        }

        // 次のミドルウェアまたはコントローラにリクエストを渡す
        $response = $next($request);

        // レスポンス後の処理：レスポンスヘッダーにカスタム情報を追加
        $response->headers->set('X-User-Status', $user ? 'active' : 'guest');

        return $response;
    }
}
```

**補足:**

- `Auth::user()` を利用して現在のユーザー情報を取得。  
- ユーザーがログインしている場合に、`isBanned()`（Userモデルに実装していると仮定）で利用停止状態かチェック。  
- 利用停止の場合、`redirect()->route('banned.notice')` で専用ページへ誘導しています。  
- レスポンス後の処理で、`X-User-Status` ヘッダーを追加しているのは、後からデバッグやフロントエンド側で確認するための例です。

---

## 2. パラメータ付きミドルウェアの実用例

次に、ユーザーのロール（権限）をチェックするミドルウェアのサンプルです。  
たとえば、管理者専用のルートにアクセスさせる前に、ユーザーが `admin` ロールを持っているかをチェックします。

### 2-1. ユーザーロールチェックミドルウェア（CheckUserRole）

**作成コマンド:**

```bash
php artisan make:middleware CheckUserRole
```

**生成されるファイル:**  
`app/Http/Middleware/CheckUserRole.php`

**サンプルコード:**

```php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class CheckUserRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string  $role  期待するユーザーロール（例："admin"）
     * @return mixed
     */
    public function handle(Request $request, Closure $next, $role)
    {
        $user = Auth::user();

        // ユーザーがログインしていない、もしくは期待するロールを持っていない場合
        if (! $user || ! $user->hasRole($role)) {
            // 403エラーを返すか、または特定のページへリダイレクトする
            abort(403, 'この操作は許可されていません。');
        }

        return $next($request);
    }
}
```

**補足:**

- `$role` はルート定義時にミドルウェアへ渡すパラメータです。  
- ユーザーがログインしていない場合や、Userモデルに実装した `hasRole()` メソッドで期待するロールを持っていない場合は、HTTP 403 エラーを返します。  
- もちろん、必要に応じてリダイレクト処理に変更することも可能です。

---

## 3. ミドルウェアの登録（Laravel 11.x ～ bootstrap/app.php）

Laravel 11.x では、ミドルウェアは **`bootstrap/app.php`** に登録します。  
以下は、グローバルミドルウェアとルートミドルウェアの登録例です。

### 3-1. グローバルミドルウェアの登録例

```php
// bootstrap/app.php

$app->middleware([
    // すべてのリクエストに適用するミドルウェア
    App\Http\Middleware\CheckForMaintenanceMode::class,
    App\Http\Middleware\CheckUserStatus::class, // 先ほど作成した利用停止ユーザーチェック
]);
```

### 3-2. ルートミドルウェアの登録例

```php
// bootstrap/app.php

$app->routeMiddleware([
    'auth'   => App\Http\Middleware\Authenticate::class,
    'role'   => App\Http\Middleware\CheckUserRole::class, // パラメータ付きミドルウェア
    'sample' => App\Http\Middleware\SampleMiddleware::class,
]);
```

---

## 4. ルート定義と実用的な使用例

実際のルート定義において、上記のミドルウェアをどのように活用するかを見てみましょう。

### 4-1. 利用停止ユーザーのリダイレクト例

利用停止ユーザー向けの通知ページ（例：banned.notice）があると仮定します。

```php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\NoticeController;

Route::group(['prefix' => 'admin'], function () {
    // ログイン関連のルート（ミドルウェア不要）
    Route::get('/login', [LoginController::class, 'showLoginForm'])->name('login');
    Route::post('/login', [LoginController::class, 'login']);

    // 通知ページ：利用停止ユーザー向け
    Route::get('/banned', [NoticeController::class, 'banned'])->name('banned.notice');

    // 認証済みユーザー向けのルートグループ
    Route::group(['middleware' => 'auth'], function () {
        // 利用停止チェックミドルウェアはグローバルに登録済み

        // 管理者のみアクセス可能なルート
        Route::group(['middleware' => 'role:admin'], function () {
            Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
        });
    });
});
```

**ポイント:**

- `/admin/banned` には、利用停止状態のユーザーがリダイレクトされます（`CheckUserStatus` ミドルウェアが働く）。
- `/admin/dashboard` は、`auth` と `role:admin` のミドルウェアが両方適用され、ログイン済みかつ管理者権限を持つユーザーのみアクセス可能です。

---

## 5. サービスプロバイダの自動登録とその違い

Laravel 11.x では、サービスプロバイダを作成すると自動的に **`bootstrap/providers.php`** に登録されるようになりました。  
サービスプロバイダは、アプリケーション起動時に一度だけ実行され、以下のような初期化処理を担当します。

### 5-1. サービスプロバイダ作成の例

```bash
php artisan make:provider CustomServiceProvider
```

生成されたサービスプロバイダは、以前は手動で `config/app.php` の `providers` 配列に追加する必要がありましたが、Laravel 11.x では自動で **`bootstrap/providers.php`** に登録されます。

**サービスプロバイダとミドルウェアの違い:**

- **ミドルウェア:**  
  → 各リクエストごとに実行される処理（例：認証、権限チェック、CSRF 保護）  
  → `bootstrap/app.php` でグローバルまたはルート単位で登録  
- **サービスプロバイダ:**  
  → アプリケーション起動時の初期化処理（例：サービスバインディング、イベントリスナー登録）  
  → 作成時に自動で `bootstrap/providers.php` に登録され、アプリ全体の基盤を構築

---

## 6. まとめ

- **カスタムミドルウェアの作成:**  
  Artisan コマンドで生成し、`handle` メソッド内でリクエスト前後の処理を実装。  
  実用例として、利用停止ユーザーのリダイレクト（`CheckUserStatus`）やパラメータ付きのロールチェック（`CheckUserRole`）を紹介。

- **Laravel 11.x の登録方式:**  
  ミドルウェアは `bootstrap/app.php` でグローバルおよびルートミドルウェアとして登録。  
  サービスプロバイダは作成時に自動で `bootstrap/providers.php` に登録され、手動設定が不要に。

- **実用的なサンプルコード:**  
  ルート定義例やコントローラと連携した利用例を充実させ、実際のアプリケーションでの利用イメージを明確化。

これらを活用することで、堅牢で保守性の高い Laravel アプリケーションを構築できるでしょう。  
ぜひ、自分のプロジェクトに合わせたカスタムミドルウェアを作成し、柔軟なリクエスト制御を実現してください！

---

### 参考リンク

- [Laravel 11 公式ドキュメント - Middleware](https://laravel.com/docs/11.x/middleware)
- [Laravel 11 公式ドキュメント - Service Providers](https://laravel.com/docs/11.x/providers)
- [Laravel 11 公式ドキュメント - Routing](https://laravel.com/docs/11.x/routing)

---

以上、実用的なカスタムミドルウェアの作成と活用例についての解説でした。  
ご質問やコメントがあれば、お気軽にお寄せください！