L

認可(ポリシー)で操作を制限する

「自分の投稿だけ編集・削除できる」といった権限の制御を、Laravelのポリシーを使って実現する方法を学びます。

広告枠(記事上)— 本番では AdSense 広告が表示されます

前の単元では「ログインしているか」で制御しました。しかし実際のアプリでは、もう一歩進んで「この投稿を編集できるのは、書いた本人だけ」のような制御が必要です。これが 認可(権限のチェック) です。

認証と認可のちがい

混同しやすいので、ここで整理します。

  • 認証(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アプリを実際に作ります
広告枠(記事下)— 本番では AdSense 広告が表示されます