認可(ポリシー)で操作を制限する
「自分の投稿だけ編集・削除できる」といった権限の制御を、Laravelのポリシーを使って実現する方法を学びます。
前の単元では「ログインしているか」で制御しました。しかし実際のアプリでは、もう一歩進んで「この投稿を編集できるのは、書いた本人だけ」のような制御が必要です。これが 認可(権限のチェック) です。
認証と認可のちがい
混同しやすいので、ここで整理します。
- 認証(authentication)…「あなたは誰か」を確認する(ログイン)。
- 認可(authorization)…「あなたは、それをしてよいか」を判断する(権限)。
ログインしている(認証OK)人でも、他人の投稿は編集できない(認可NG)——というように、2つは役割が違います。
ポリシーを作る
Laravel では、あるモデルに対する「誰が何をしてよいか」のルールを ポリシー というクラスにまとめます。make:policy で作成します。
php artisan make:policy PostPolicy --model=Post
app/Policies/PostPolicy.php が作られます。たとえば「更新してよいか」のルールを update() メソッドに書きます。
public function update(User $user, Post $post): bool
{
// 投稿の user_id と、操作している人のIDが一致すれば許可
return $user->id === $post->user_id;
}
「ログイン中の人のID」と「その投稿の投稿者ID」が同じなら true(=本人なので許可)という意味です。
コントローラでチェックする
コントローラでは、Gate::authorize() を呼ぶだけでこのルールが適用されます。ファイル先頭に use Illuminate\Support\Facades\Gate; を追加して使います。
use Illuminate\Support\Facades\Gate;
public function update(Request $request, Post $post)
{
Gate::authorize('update', $post);
// ここに来られるのは、許可された人だけ
$post->update($request->validate([
'title' => ['required', 'max:255'],
'body' => ['required'],
]));
return redirect('/posts');
}
許可されなければ、Laravel が自動的に 403(権限なし)エラーを返し、続きは実行されません。安全です。
メモ:
$this->authorize()ではないの? 古い記事では$this->authorize('update', $post)という書き方をよく見かけます。これは Laravel 10 までの書き方で、Laravel 11 以降は基底コントローラからこの機能が外れたため、そのままでは使えません(メソッドが存在しないエラーになります)。本講座では、どこでも使えるGate::authorize()で統一します。
画面でボタンを出し分ける:@can
「編集ボタンを、編集できる人にだけ見せる」には Blade の @can を使います。
@can('update', $post)
<a href="/posts/{{ $post->id }}/edit">編集</a>
@endcan
これで、他人の投稿には編集ボタンそのものが表示されなくなります(見た目の制御)。ただし見た目だけで安心せず、コントローラ側の Gate::authorize() も必ず書いてください(本当の防御はサーバー側で行います)。
まとめ
- 認証=誰か、認可=してよいか。役割が違う。
- モデルごとの権限ルールは ポリシーにまとめる。
make:policy PostPolicy --model=Post。 - コントローラで
Gate::authorize('update', $post)を呼べばルールが適用され、NGなら403(Laravel 11以降は$this->authorizeではなくGate::authorizeを使う)。 - Blade の
@canでボタンを出し分けられるが、サーバー側のGate::authorize()が本当の防御。 - 第7章は完了です。次章では、ここまでの知識を総動員してCRUDアプリを実際に作ります。