#16 Laravel基礎

ゲートとポリシーで認可を実装する

認証と認可の違い

  • 認証(Authentication):あなたは誰か?(ログイン)
  • 認可(Authorization):あなたにそれをする権限はあるか?

Laravelの ゲート? 「この操作をしてよいか」という認可ルールを定義する仕組み。`Gate::allows()`でシンプルに確認できる。 ポリシー? モデルに紐づいた認可ロジックをまとめるクラス。「このユーザーはこの投稿を編集できるか」などのルールをまとめて管理できる。 は「認可」を管理するための仕組みです。


ゲート(Gate)

ゲート? 「この操作をしてよいか」という認可ルールを定義する仕組み。`Gate::allows()`でシンプルに確認できる。 はシンプルなクロージャーで認可ロジックを定義します。特定のモデルに紐づかないルールに向いています。

ゲートを定義する

// 📁 app/Providers/AppServiceProvider.php

use Illuminate\Support\Facades\Gate;

public function boot(): void
{
    // 管理者かどうかチェックするゲート
    Gate::define('admin-only', function ($user) {
        return $user->role === 'admin';
    });

    // 投稿を更新できるかチェックするゲート
    Gate::define('update-post', function ($user, $post) {
        return $user->id === $post->user_id;
    });
}

ゲートを使う

コントローラーで:

// 📁 app/Http/Controllers/PostController.php

use Illuminate\Support\Facades\Gate;

public function update(Request $request, Post $post)
{
    // 権限がなければ403エラー
    Gate::authorize('update-post', $post);

    $post->update($request->only('title', 'body'));
    return redirect()->route('posts.show', $post);
}

ビューで:

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

ポリシー(Policy)

ポリシー? モデルに紐づいた認可ロジックをまとめるクラス。「このユーザーはこの投稿を編集できるか」などのルールをまとめて管理できる。 は特定のモデルに関する認可ロジックをクラスにまとめます。CRUD操作の認可が複数ある場合に整理しやすくなります。

ポリシーを生成する

php artisan make:policy PostPolicy --model=Post
<?php
// 📁 app/Policies/PostPolicy.php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    // 一覧を見られるか(全員OK)
    public function viewAny(User $user): bool
    {
        return true;
    }

    // 詳細を見られるか
    public function view(User $user, Post $post): bool
    {
        return true;
    }

    // 作成できるか
    public function create(User $user): bool
    {
        return true;
    }

    // 更新できるか(自分の投稿だけ)
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }

    // 削除できるか(自分の投稿、または管理者)
    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id || $user->role === 'admin';
    }
}

ポリシーを登録する

モデルと同名のポリシーを app/Policies/ に置けば自動で認識されます(Laravel 9以降)。

コントローラーでポリシーを使う

authorize() メソッドはポリシーも自動で参照します。

// 📁 app/Http/Controllers/PostController.php

public function update(Request $request, Post $post)
{
    // PostPolicy の update() を自動で呼ぶ
    $this->authorize('update', $post);

    $post->update($request->only('title', 'body'));
    return redirect()->route('posts.show', $post);
}

public function destroy(Post $post)
{
    $this->authorize('delete', $post);
    $post->delete();
    return redirect()->route('posts.index');
}

ビューでポリシーを使う

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

@can('delete', $post)
    <form method="POST" action="{{ route('posts.destroy', $post) }}">
        @csrf
        @method('DELETE')
        <button type="submit">削除</button>
    </form>
@endcan

ポリシーでモデルを使わないアクション

create のように特定のインスタンスが存在しない場合は、モデルの第2引数を省略します。

// コントローラー
$this->authorize('create', Post::class);

// ビュー
@can('create', App\Models\Post::class)
    <a href="{{ route('posts.create') }}">新規作成</a>
@endcan

まとめ

  • ゲートは AppServiceProvider にクロージャーで定義する(シンプルなルール向け)
  • ポリシーはモデルに紐づく認可ロジックをクラスにまとめる(CRUD向け)
  • コントローラーでは $this->authorize() で認可チェックできる
  • ビューでは @can / @cannot ディレクティブを使う

次回はファイルのアップロードとストレージ管理を学びます。