22.

Laravel ルート認証化完全ガイド — middleware と Gate

編集
この記事の要点
  • Laravel のルートに認証を掛けるには middleware("auth") を付与
  • API 認証は auth:sanctum / auth:api / auth:passport
  • メール認証必須は verified、認可は can:ability,Model
  • ゲスト専用 (ログイン後アクセス不可) は guest middleware
  • 細かい認可は Gate / Policy、Form Request の authorize() でリクエスト単位に

基本: auth middleware

ログイン必須にしたいルートに auth middleware を付けます:

// routes/web.php
use App\Http\Controllers\DashboardController;

// 単一ルートに付与
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth')
    ->name('dashboard');

// グループに一括付与
Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::delete('/account', [AccountController::class, 'destroy']);
});

// プレフィックス + 名前空間 + middleware
Route::middleware(['auth', 'verified'])
     ->prefix('admin')
     ->name('admin.')
     ->group(function () {
        Route::get('/users', [Admin\UserController::class, 'index'])->name('users.index');
     });

未ログインで /dashboard にアクセスすると /login へリダイレクトされます。

認証 guard の指定

middleware用途備考
authWeb セッション認証デフォルト guard
auth:sanctumSPA / API トークンLaravel 推奨
auth:apiPassport API トークン (旧)Passport 利用時
auth:adminカスタム guard (admin)config/auth.php で定義
auth.basicHTTP Basic 認証クイック保護用
verifiedメール認証済のみauth と併用
guest未ログインのみlogin / register 画面用
password.confirmパスワード再確認センシティブ操作前

API ルート (Sanctum)

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn(Request $r) => $r->user());
    Route::apiResource('posts', PostController::class);
});

// 公開API + 認証必須API を併存
Route::get('/public/posts', [PublicPostController::class, 'index']);
Route::middleware('auth:sanctum')->get('/private/posts', [PrivatePostController::class, 'index']);

認可: can middleware

「自分の投稿しか編集できない」等の所有者チェックは Policy + can middleware:

// routes/web.php
Route::put('/posts/{post}', [PostController::class, 'update'])
    ->middleware(['auth', 'can:update,post']);

// app/Policies/PostPolicy.php
namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

// app/Providers/AuthServiceProvider.php
protected $policies = [
    Post::class => PostPolicy::class,
];

Form Request での authorize()

// app/Http/Requests/PostUpdateRequest.php
class PostUpdateRequest extends FormRequest
{
    public function authorize(): bool
    {
        // route("post") が暗黙バインドの Post モデル
        return $this->user()->id === $this->route('post')->user_id;
    }

    public function rules(): array
    {
        return ['title' => 'required|max:100'];
    }
}

authorize()false を返すと 403 Forbidden

ゲスト専用ルート

ログイン済ユーザーが /login にアクセスしたら /dashboard へリダイレクトしたい:

// routes/web.php
Route::middleware('guest')->group(function () {
    Route::get('/login', [LoginController::class, 'show'])->name('login');
    Route::post('/login', [LoginController::class, 'store']);
    Route::get('/register', [RegisterController::class, 'show'])->name('register');
    Route::post('/register', [RegisterController::class, 'store']);
});

// app/Http/Middleware/RedirectIfAuthenticated.php
public function handle($request, Closure $next, ...$guards)
{
    foreach ($guards as $guard) {
        if (Auth::guard($guard)->check()) {
            return redirect('/dashboard');
        }
    }
    return $next($request);
}

ログイン後リダイレクト先のカスタマイズ

// app/Http/Middleware/Authenticate.php
protected function redirectTo($request)
{
    if (! $request->expectsJson()) {
        return route('login');
    }
}

// LoginController で 認証成功後のリダイレクト
protected $redirectTo = '/dashboard';

// または method override
protected function redirectTo()
{
    return Auth::user()->isAdmin
        ? '/admin'
        : '/dashboard';
}

SPA + Sanctum パターン

// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000')),

// routes/api.php
Route::middleware(['auth:sanctum'])->group(function () {
    Route::get('/me', fn(Request $r) => $r->user());
});
// フロント (Vue / React) 側
// CSRF Cookie を取得
await axios.get('/sanctum/csrf-cookie');

// ログイン
await axios.post('/login', { email, password });

// 認証必須 API
const res = await axios.get('/api/me');

middleware の組合せ実例

// 管理画面: 認証 + メール認証 + 管理者ロール + パスワード再確認
Route::middleware([
    'auth',
    'verified',
    'role:admin',
    'password.confirm:120',  // 120分以内に再確認
])->prefix('admin')->group(function () {
    Route::get('/users/{user}/destroy', [Admin\UserController::class, 'destroy'])
        ->middleware('can:delete,user');
});

FAQ

Q: middleware を全ルートに掛けたい
A: app/Http/Kernel.php$middleware (グローバル) または $middlewareGroups (web/api) に登録。

Q: 認証エラー時に JSON を返したい
A: Authenticate::redirectTo() 内で $request->expectsJson() を判定。null を返すと自動で 401 JSON。

Q: 複数 guard を OR で組合せたい
A: auth:web,admin のようにカンマ区切り。どちらかに通れば OK。

Q: middleware の順番は重要?
A: 重要。authverifiedcan の順が一般的。auth 前に can を置くと user が null でエラー。

編集
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編)