🦌

Laravelの認可機構GateとPolicyを紐解く

に公開

前書き

Laravelのフレームワークには認可に伴う機能として、GatePolicyが標準で提供されている。
この二つの機能は似ているようで異なる特徴を持っており、適切に使い分けることが重要である。
本記事では、GatePolicyの違いに焦点を当て、それぞれの特徴や適切な採用するシチュエーションについて解説する。
理解を助けるため、オフィスビルのセキュリティシステムを例として用いる。

Gateとは

まずは、Gateについて説明する。
名前が示すとおり、Gateはオフィスビルの入口にある中央受付のようなものである。
すべての訪問者はこの受付を通過する必要があり、ビル全体への入館許可があるかどうかを判断される。

Gateは技術的には、柔軟なクロージャーを使用して定義することができる権限チェックの仕組みである。

このアプローチは以下の場合に最適であると考える。

  • アプリケーション全体に関わる一般的な権限チェック
  • シンプルな条件に基づく判断
  • モデルに特化していないグローバルなルール

Policyとは

次に、Policyについて説明する。
Policyは各部屋や各フロアに配置された専用セキュリティシステムのようなものである。
ここで部屋やフロアはLaravelのモデル(データベースの各テーブルを表すクラス)に相当する。
特定の部屋やリソースへのアクセス権限があるかといった、より細かい粒度の判断を行う。

Policyは特定のモデルに関連する権限チェックを行うためのクラスであり、各メソッドは特定の操作(例:作成、更新、削除)に対する権限を確認する。

  • リソース(モデル)中心の設計
  • メソッドごとにグループ化されたポリシー定義
  • 特定のモデルに対するCRUD操作の権限管理
  • 複雑な認可ロジックの実装

GateとPolicyの違い

両者の本質的な違いは適用範囲と責任にある。
Gateは全体の入口(アプリケーション全体)の権限を管理し、Policyは特定の部屋やフロア(特定のモデル)に対するアクセス権限を管理する。

具体的には、以下のような違いがある。

  • Gateは特定のモデルに関連しない一般的な権限チェックを行う
  • Policyは特定のモデルに紐づいた権限チェックを行う

GateとPolicyの関係図

使用例

Gateの事例

私の経験では、RBAC(Role-Based Access Control:役割ベースのアクセス制御)のような、モデルに直接関連しない一般的な権限チェックにはGateが効果的である。

例えば、管理者権限を持つユーザーかどうかを確認する場合、以下のようにGateを使用することができる。

// AppServiceProviderなどで定義
Gate::define('is-admin', function (User $user) {
    return $user->role === 'admin';
});

// 使用例
if (Gate::allows('is-admin')) {
    // 管理者向けの処理
}

Policyの事例

一方、特定のモデルに対する操作権限の管理にはPolicyが適している。
私の実装経験では、ユーザーが自分の投稿のみを編集できるようにするケースが典型的な例である。

class PostPolicy
{
    // 更新権限のチェック
    public function update(User $user, Post $post)
    {
        return $user->id === $post->user_id;
    }
    
    // 削除権限のチェック
    public function delete(User $user, Post $post)
    {
        return $user->id === $post->user_id || $user->isAdmin();
    }
}

// 使用例
if ($user->can('update', $post)) {
    // 投稿更新処理
}

ハイブリッドアプローチ

GatePolicyは排他的なものではなく、むしろ互いを補完するものである。
実際のアプリケーションでは、両方を組み合わせた「ハイブリッド」に運用することができる。

例えば、以下のように組み合わせることができる。

// Gateで全体的な権限を定義
Gate::define('access-admin-panel', function (User $user) {
    return $user->hasRole('admin') || $user->hasRole('editor');
});

// Policyで特定モデルへの操作権限を定義
class ArticlePolicy
{
    public function create(User $user)
    {
        // Gateを利用しつつ、追加条件を設定
        return Gate::allows('access-admin-panel', $user) && $user->emailVerified();
    }
}

まとめ

GatePolicyは、Laravelの認可機能を実装するための強力かつ柔軟なツールである。
Gateはアプリケーション全体の一般的な権限管理に適しており、Policyは特定のモデルに対する詳細な権限制御に向いている。
適材適所で使い分け、あるいは組み合わせることで、セキュアで管理しやすい認可システムを構築できる。
実装する際は、アプリケーションの規模や要件に応じてアプローチを選択することが重要である。

参考リンク

GitHubで編集を提案

Discussion