第08回: Policy/Gateの実践認可 — 「認証」と「認可」、まだ混同していませんか?

章: 第3章: データ層の最適化

「ログインしているのに自分の記事が削除できてしまった」「管理者のみ操作できるはずなのに他のユーザーも操作できた」――認可の実装漏れは進次的なセキュリティリスクを生みます。

LaravelのPolicyとGateは、認可ロジックを専用クラスに集約 し、ControllerやViewで一貫した認可チェックを実現する仕組みです。認可アクションが一箇所にまとまるので、レビューもテストも容易になります。

なぜPolicy/Gateが重要なのか

認可をControllerに直書きすると次の問題が起きます。

  • if文が各Controllerに散らばり、修正漏れが発生する
  • 同じ認可ルールの要件が変わったときに大幅な流し替えが必要になる
  • Bladeテンプレートでの認可がアドホックになりやすい

チェックポイント: 認証(誤りなくログインしているか?)と認可(そのユーザーはこの操作をしていいか?)は別物です。まずこの区別を明確にすることから始めましょう。

Policy vs Gate — 使い分け

観点 Gate Policy
適した用途 モデルに紐づかない認可 モデル単位の認可(CRUD権限)
登録場所 AuthServiceProvider php artisan make:policy
Blade @can('admin') @can('update', $post)
Controller Gate::allows(...) $this->authorize('update', $post)

実装例


<?php
// PostPolicy.php
public function update(User $user, Post $post): bool
{
    return $user->id === $post->user_id;
}

// Controller
public function update(UpdatePostRequest $request, Post $post)
{
    $this->authorize('update', $post);
    $post->update($request->validated());
}

Bladeでの認可制御


@can('update', $post)
    <a href="{{ route('posts.edit', $post) }}">編集</a>
@endcan

Controllerで authorize() しているため、Bladeの @can と両方で同じPolicyメソッドが呼ばれます。標定一箇所から一貫した認可を実現できます。

まとめ & 次のステップ

  • 認可ロジックをPolicyに集約することで、修正漏れとController脹肥ㅯ化を防ぐ
  • $this->authorize('update', $post) で自動403レスポンス ― 例外処理不要
  • @can ディレクティブでBladeとPolicyが尚統一される
  • 認可テストは actingAs($user)->... で正しいユーザーの権限が確認できる

次回は 第09回: Queue再試行と失敗ジョブ設計 で、非同期処理の障害耐性を設計する方法を学びます。

Related Articles