20.

Laravel 認証必須化 (auth Middleware) 完全ガイド|Web / API / Sanctum 統合

編集
この記事の要点
  • Laravel で「ログインしないと見せない」はルートに middleware('auth') を付けるのが基本。グループで複数ルートに一括適用
  • Controller 側で必須化するなら コンストラクタ$this->middleware('auth')except / only でアクション単位除外可能
  • API は Sanctum (auth:sanctum)、SPA は同じく Sanctum の Cookie 認証、Mobile は Token 認証で統一できる
  • 未認証時のリダイレクト先は app/Http/Middleware/Authenticate.phpredirectTo() で制御。API リクエストは JSON 401 を返すべき
  • スターターキット (Breeze / Jetstream) を使えば、ログイン画面・登録・パスワードリセットまで一括スキャフォールド可能

Laravel の認証システム概要

Laravel は Guard (認証方式)Provider (ユーザー取得元) を組み合わせて認証を構成します。設定は config/auth.php。デフォルトは Web Guard (Session ベース) + Eloquent User モデル。

// config/auth.php (抜粋)
'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

'guards' => [
    'web' => ['driver' => 'session', 'provider' => 'users'],
    'api' => ['driver' => 'token',   'provider' => 'users'],  // 旧 token
    // Sanctum 利用時は別途設定
],

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

パターン 1: ルート単位の auth Middleware

もっともシンプルで頻出するパターン。routes/web.php でルートに auth ミドルウェアを付与します。

// routes/web.php
use Illuminate\Support\Facades\Route;

// 公開ページ (ログイン不要)
Route::get('/', [HomeController::class, 'index']);
Route::get('/about', fn () => view('about'));

// ログイン必須エリア
Route::middleware('auth')->group(function () {
    Route::get('/dashboard',   [DashboardController::class, 'index']);
    Route::get('/profile',     [ProfileController::class, 'show']);
    Route::put('/profile',     [ProfileController::class, 'update']);
    Route::post('/logout',     [AuthController::class,    'logout']);
});

// 認証 + 検証済メール必須
Route::middleware(['auth', 'verified'])->group(function () {
    Route::get('/billing', [BillingController::class, 'index']);
});

// 認証 + 管理者ロールのみ
Route::middleware(['auth', 'role:admin'])->group(function () {
    Route::get('/admin', [AdminController::class, 'index']);
});

パターン 2: Controller コンストラクタで一括

1 つの Controller のほぼ全アクションがログイン必須なら、コンストラクタで指定が楽です。

namespace App\Http\Controllers;

class ArticleController extends Controller
{
    public function __construct()
    {
        // 全アクションに auth を適用
        $this->middleware('auth');

        // 例外: 一覧と詳細だけは公開
        $this->middleware('auth')->except(['index', 'show']);

        // または特定アクションのみ
        $this->middleware('auth')->only(['create', 'store', 'update', 'destroy']);
    }
}

Laravel 11+ では Controller のコンストラクタ Middleware が削除され、ルート側で指定するスタイルに統一されました。バージョンに応じて使い分け。

パターン 3: Laravel 11+ 推奨スタイル

// Laravel 11+ では HasMiddleware インターフェース
namespace App\Http\Controllers;

use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

class ArticleController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',                                          // 全アクション
            new Middleware('auth', except: ['index', 'show']), // 一部除外
            new Middleware(['auth', 'verified'], only: ['edit', 'update']),
        ];
    }

    public function index() { /* 公開 */ }
    public function show($id) { /* 公開 */ }
    public function edit($id) { /* 認証 + 検証済 */ }
}

主要な認証 Middleware

Middleware役割未認証時
authデフォルト Guard で認証必須login ルートへリダイレクト
auth:webweb Guard を明示同上
auth:apiapi Guard401 JSON
auth:sanctumSanctum (SPA + API + Mobile)401 JSON or リダイレクト
auth.basicHTTP Basic 認証401 + WWW-Authenticate
auth.sessionセッションがあれば認証
guest未ログイン専用 (ログイン画面など)ホームへリダイレクト
verifiedメール検証済必須verification 画面へ
password.confirm直近で再認証必須パスワード再確認画面

未認証時のリダイレクト先カスタマイズ

// Laravel 10 以前: 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 リクエストは null を返して 401 を発生させる
        if ($request->expectsJson()) {
            return null;
        }
        // ブラウザはログイン画面へ
        return route('login');
    }
}
// Laravel 11+: bootstrap/app.php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->redirectGuestsTo(fn () => route('login'));
        $middleware->redirectUsersTo('/dashboard');
    })
    ->create();

Blade での出し分け

@auth
    {{-- ログイン中だけ表示 --}}
    <p>こんにちは、{{ Auth::user()->name }} さん</p>
    <form method="POST" action="{{ route('logout') }}">
        @csrf
        <button>ログアウト</button>
    </form>
@endauth

@guest
    {{-- 未ログイン時だけ表示 --}}
    <a href="{{ route('login') }}">ログイン</a>
    <a href="{{ route('register') }}">新規登録</a>
@endguest

@auth('admin')
    {{-- 別 Guard で判定 --}}
    <a href="{{ route('admin.dashboard') }}">管理画面</a>
@endauth

Sanctum での API 認証

SPA / モバイル / API のどれを書いていても Sanctum 1 つで網羅できるのが現代の Laravel スタンダードです。

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $r) => $r->user());
    Route::apiResource('articles', ArticleController::class);
});

// トークン発行 (モバイル / 外部システム)
$user = User::find(1);
$token = $user->createToken('mobile-app')->plainTextToken;
// → ヘッダ: Authorization: Bearer 1|abc...

// User モデル
class User extends Authenticatable
{
    use HasApiTokens;   // ← Sanctum 必須トレイト
}

スターターキットを使う

ログイン画面・登録画面・パスワードリセットを自分で書く必要はありません。Laravel 公式のスキャフォールドを使いましょう。

キット特徴用途
Breeze★ 最小構成 (Blade / Vue / React / API)シンプル CRUD アプリ
JetstreamTeams / 2FA / API トークン / Profile 管理SaaS
FortifyUI 無しのバックエンドのみ独自フロント / Inertia 系
# Breeze (Blade 版) の例
composer require laravel/breeze --dev
php artisan breeze:install blade
npm install && npm run dev
php artisan migrate

# /login /register /password/reset /verify-email
# ルートが自動生成 + UI 完成

パスワード再確認

支払い情報変更や退会などセンシティブな操作には、ログイン済でも再度パスワード確認を求めます。

Route::middleware(['auth', 'password.confirm'])->group(function () {
    Route::delete('/account', [AccountController::class, 'destroy']);
    Route::post('/billing/card', [BillingController::class, 'updateCard']);
});

// 確認後の有効期限 (秒) は config/auth.php
'password_timeout' => 10800,   // 既定 3 時間

API リクエストへの 401 JSON 返却

SPA / モバイルからの API リクエストは HTML へリダイレクトされても困ります。Accept: application/json ヘッダ付きなら自動で 401 JSON が返ります。

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
  "message": "Unauthenticated."
}

テスト

use App\Models\User;

it('未ログインユーザーはダッシュボードからリダイレクトされる', function () {
    $this->get('/dashboard')->assertRedirect('/login');
});

it('ログイン済ならダッシュボードが見える', function () {
    $user = User::factory()->create();
    $this->actingAs($user)
        ->get('/dashboard')
        ->assertOk();
});

it('API は 401 JSON を返す', function () {
    $this->getJson('/api/user')->assertStatus(401);
});

FAQ

Q: ログイン後に元のページに戻したい
A: auth Middleware は未認証時に url()->previous() をセッションに保存し、ログイン後 redirect()->intended('/default') で復元します。標準でこの動作が含まれているはず。

Q: 一部の URL だけログインを免除したい
A: ルートを別グループに分け、Route::middleware('auth')->group(...) の外に置きます。Controller 単位なら except 引数で指定。

Q: 複数の認証 (顧客 / 管理者) を使い分けたい
A: config/auth.php に複数 Guard と Provider を定義し、auth:admin のように Guard 名付きで Middleware 指定します。

Q: ログインしているのに毎回ログイン画面に戻される
A: セッションドライバの設定ミスが多い。SESSION_DRIVER=file なら storage/framework/sessions の権限、cookie なら SESSION_DOMAIN 設定、HTTPS なら SESSION_SECURE_COOKIE=true を確認。

Q: API でログイン状態をフロントに通知したい
A: SPA + Sanctum の Cookie 認証なら /api/user を叩いて 200 ならログイン中、401 なら未ログインと判定。CSRF は /sanctum/csrf-cookie 先取りが必要。

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

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