45.

Laravel Middleware で Auth を使う完全ガイド

編集
この記事の要点
  • Auth::check() / Auth::user() / Auth::id() は Middleware でも使用可
  • ただしweb ミドルウェアグループに属している必要がある (StartSession / EncryptCookies が前提)
  • API はguard 指定が必須: Auth::guard("sanctum")->check()
  • 未認証時はAuthenticate.php の redirectTo() でリダイレクト先を制御
  • Laravel 11 は bootstrap/app.phpwithMiddleware で登録 (Kernel.php 廃止)

結論: Middleware で Auth ヘルパーを使うコード

<?php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;

class EnsurePremiumUser
{
    public function handle(Request $request, Closure $next): Response
    {
        // 認証チェック
        if (! Auth::check()) {
            return redirect()->route('login');
        }

        // ユーザを取得して属性チェック
        $user = Auth::user();
        if (! $user->is_premium) {
            return redirect()->route('upgrade')
                ->with('error', 'Premium プランが必要です');
        }

        // 認証 ID をログに
        \Log::info('Premium access', ['user_id' => Auth::id()]);

        return $next($request);
    }
}

Auth Facade と Helper の対応

FacadeHelper意味
Auth::check()auth()->check()認証済か (bool)
Auth::user()auth()->user()User モデル (or null)
Auth::id()auth()->id()ユーザ ID (int or null)
Auth::guest()auth()->guest()未認証か
Auth::guard('api')auth('api')ガード指定
Auth::logout()auth()->logout()ログアウト

Middleware Group とセッション

Auth::check() はセッションを使うため、StartSession ミドルウェアが先に動いている必要があります。Laravel のデフォルトでは web グループに StartSession / EncryptCookies が含まれていて、api グループには含まれません。

Laravel 10 以前 (Kernel.php)

// app/Http/Kernel.php
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' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

protected $middlewareAliases = [
    'auth'         => \App\Http\Middleware\Authenticate::class,
    'auth.basic'   => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'premium'      => \App\Http\Middleware\EnsurePremiumUser::class,  // ★ 登録
];

Laravel 11 (bootstrap/app.php)

Laravel 11 では Kernel.php が廃止され、すべて bootstrap/app.php で設定します:

// bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->alias([
            'premium' => \App\Http\Middleware\EnsurePremiumUser::class,
        ]);

        // web グループに独自ミドル追加
        $middleware->web(append: [
            \App\Http\Middleware\TrackLastActivity::class,
        ]);

        // api グループに Sanctum stateful
        $middleware->statefulApi();
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

ルートでの利用

// routes/web.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PremiumController;

Route::middleware(['auth', 'premium'])->group(function () {
    Route::get('/dashboard', [PremiumController::class, 'index']);
    Route::get('/reports',   [PremiumController::class, 'reports']);
});

// 単一ルートに付与
Route::get('/profile', [ProfileController::class, 'show'])
    ->middleware('auth');

API での認証 (Sanctum)

API では Cookie セッションではなく Bearer Token を使うため、Auth::guard('sanctum') を明示します:

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;

class CheckApiToken
{
    public function handle(Request $request, Closure $next): Response
    {
        if (! Auth::guard('sanctum')->check()) {
            return response()->json(['error' => 'Unauthenticated'], 401);
        }

        $user = Auth::guard('sanctum')->user();
        $request->setUserResolver(fn () => $user);   // 後続で Auth::user() でも取れるように

        return $next($request);
    }
}

config/auth.php の guards

return [
    'defaults' => [
        'guard'     => 'web',
        'passwords' => 'users',
    ],

    'guards' => [
        'web' => [
            'driver'   => 'session',
            'provider' => 'users',
        ],
        'api' => [                          // 古い形 (passport)
            'driver'   => 'passport',
            'provider' => 'users',
        ],
        'sanctum' => [                      // Sanctum 専用
            'driver'   => 'sanctum',
            'provider' => 'users',
        ],
    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model'  => App\Models\User::class,
        ],
    ],
];

未認証時のリダイレクト先を制御

// app/Http/Middleware/Authenticate.php
namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Http\Request;

class Authenticate extends Middleware
{
    protected function redirectTo(Request $request): ?string
    {
        // API 経路はリダイレクトせず JSON 401 を返す
        if ($request->expectsJson()) {
            return null;
        }

        // 管理画面は別のログインへ
        if ($request->is('admin/*')) {
            return route('admin.login');
        }

        return route('login');
    }
}

Closure-based Middleware (Laravel 11)

クラスを作らず、ルートに直接クロージャミドルウェアを書く方法:

// routes/web.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

Route::get('/admin', function () {
    return view('admin.index');
})->middleware(function (Request $request, Closure $next) {
    if (! Auth::check() || ! Auth::user()->is_admin) {
        abort(403);
    }
    return $next($request);
});

Middleware で Auth が null になる原因

症状原因対処
Auth::check() が常に falseroutes/api.php に置いたweb グループにする or Sanctum guard 指定
Auth::user() が nullSubstituteBindings より前で呼んでいる$middlewareAliases の順序を後ろに
セッションが消えるSESSION_DOMAIN ミス.env の SESSION_DOMAIN を修正
Auth::guard('web')->user() のみ取れるconfig/auth.php で defaults.guard が webguard 明示すれば OK

FAQ

Q: コンストラクタで Auth::user() が null になる
A: Controller のコンストラクタはセッション初期化前なので null。$this->middleware(function ($request, $next) {...}) パターンで参照するか、メソッド内で呼びます。

Q: API でも CSRF ミドルが効いて 419 になる
A: routes/api.php に置いたか、bootstrap/app.php の statefulApi 設定を見直してください。

Q: Auth::user() の型を Phpstan が User として認識しない
A: /** @var \App\Models\User $user */ で型ヒント追加、または config/auth.php の providers.users.model が正しいか確認。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. インストールと設定
  2. クイックスタート & チュートリアル(初心者向け)
  3. クイックスタート & チュートリアル(中級者向け)
  4. ルーティング
  5. Bladeテンプレート(ビュー/レイアウト)
  6. コントローラー
  7. マイグレーションとテーブル定義
  8. データベースの設定
  9. Eloquentモデル (ORM)
  10. SQLとクエリビルダー
  11. バリデーション
  12. .envファイルの設定値へのアクセス
  13. 動作環境による分岐処理
  14. configフォルダ配下の設定値へのアクセス
  15. assetヘルパーを利用したpublicフォルダへのアクセス
  16. storageフォルダへのアクセス
  17. アプリケーション名の変更
  18. メンテナンス
  19. ログイン画面(認証システム)の作成
  20. ログインの必須化
  21. ログインユーザー情報の取得
  22. ルートの認証化
  23. 本番サーバーへのデプロイ方法
  24. 多言語化
  25. csrf_field
  26. ファイルのダウンロード
  27. CSVのアップロードおよび読み込み(maatwebsite/excel)
  28. ページタイトルの設定
  29. コマンド一覧
  30. エラー一覧
  31. SQLの実行ログ出力方法
  32. キャッシュのクリア
  33. Selectの結果の最初もしくは最後に任意の値を追加する方法
  34. ajaxでPOST通信する際の注意点
  35. ソーシャルログインの実装
  36. セッション情報の確認
  37. ログイン、ユーザー登録、パスワードリセット後のリダイレクト先の変更方法
  38. redirectやreturn viewにメッセージを付与する方法
  39. クッキー(cookie)の設定と取得
  40. クラスの再読み込み
  41. csrfの有効時間を変更する方法
  42. ViewComposerを用いてviewに共通の値を付与する方法
  43. View::shareを用いて共通の値を各ビューに渡す方法
  44. ミドルウェアを用いた処理の共通化
  45. Middleware内でAuth::check()などを使用する方法
  46. Controller以外でリダイレクトする方法
  47. セッションの値の取得/保存/更新/削除
  48. $requestの値を変更する方法
  49. 常時SSL化
  50. ページング(ページネーション)をする方法
  51. vue.jsとの連携
  52. Vue.jsと連携するSPA実行環境構築
  53. .envの値をvue.jsで参照する方法
  54. vue.jsを本番環境にリリースする方法
  55. could not find driver(Windows, MySQL編)

最近更新/作成されたページ