章: 第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再試行と失敗ジョブ設計 で、非同期処理の障害耐性を設計する方法を学びます。