PHPにおける権限と認可の設計は、プロファイルを割り当てる画面だけでは解決しません。同じ操作であっても、実行者、所属組織、対象データ、そのデータの状態によって判断が変わるときに問題が生じます。これらの条件がコントローラー、クエリ、テンプレート、UIバリデーションに分散していると、システムにはレビューが困難な例外が蓄積されます。
目標は、すべての判断を明示的、反復可能、かつ検証可能にすることです。すなわち、あるアイデンティティがコンテキスト内のリソースに対して操作を試み、ポリシーが許可の可否を決定します。このアプローチにより、曖昧な運用ルールは、プロダクト、運用、開発が共同でレビューできる技術的な統制へと変換されます。
アイデンティティ、認可、データスコープを分離する

認証はユーザーが誰であるかに答えるものであり、セッション、認証情報、アイデンティティプロバイダー、トークンが対象です。認可はそのアイデンティティが何をできるかに答えます。後者を前者だけから推測したり、両者を単一のレイヤーとして扱ったりするべきではありません。
ロールは、組織管理者、サポート担当者、承認者などの責務をまとめます。権限は、たとえばinvoice.read、invoice.approve、member.inviteのような具体的な操作を表します。スコープは、その操作がどのリソースに対して有効かを定めます。たとえば、ある組織の請求書、ある部門の案件、自身のレコードなどです。
この区別により、よくある誤りを防げます。請求書の閲覧権限を付与したからといって、すべての請求書を閲覧できると想定してはなりません。ポリシーは、リソースがアクティブな組織に属するか、ユーザーに該当部門が割り当てられているか、リソースの状態が要求された操作を許容するかを、なお確認する必要があります。
操作からアクセスマトリクスを構築する
クラスやパッケージを選ぶ前に、実際のリソースと操作を列挙してください。「管理する」のような曖昧なラベルではなく、注文を作成する、注文を見る、下書きを修正する、注文を承認する、注文をキャンセルする、注文をエクスポートする、メンバーを変更する、といったビジネス上の動詞を使用します。
各操作について、業務部門と次の4項目を合意します。
- 保護対象のリソースとアクション。
- 要求できるプロファイル。
- 適用されるデータスコープ:組織、部門、所有者、ポートフォリオ、または割り当て。
- コンテキストおよび状態の条件:アクティブな組織、有効な委任、業務時間、または下書き中の文書。
作成されたマトリクスは認可コードではなく、レビュー可能な仕様です。また、未決定の判断を見つけることも強制します。サポートが「注文を閲覧できる」と記載する場合、個人データ、添付文書、クローズ済み注文、すべての組織の情報を閲覧できるかを具体化する必要があります。
小さく安定したアクションを優先する
過度に広いアクションは権限を集中させ、最小権限の適用を困難にします。order.readとorder.export、あるいはuser.updateとuser.assign_roleを分離すれば、正確にアクセスを付与できます。一方で、個別のケースごとに権限を作成するのも適切ではありません。違いがリソースに依存する場合、それは通常、新しいロールではなくポリシーの条件です。
ロール、権限、属性、コンテキストを選択する
シンプルなロールは、安定したプロファイルが少なく、操作がデータにほとんど依存しない場合に機能します。導入の出発点として適していますが、manager_con_exportacionやsupervisor_solo_unidad_norteのような名前が現れると脆弱になります。こうした組み合わせは、例外を恒久的なプロファイルとしてコード化しています。
明示的な権限は、責務をプロファイルから切り離し、管理可能な形で能力を割り当てるのに適しています。属性は、判断が主体、リソース、環境のプロパティに依存する場合に役立ちます。たとえば、組織、部門、分類、所有者、国、リスクレベルです。アクティブな委任や承認フェーズのような一時的な条件が関与する場合は、コンテキストルールがモデルを補完します。
実務では、ハイブリッドモデルのほうが保守しやすいことが一般的です。ロールが基本権限を付与し、ポリシーがユーザーとリソースの属性を評価し、コンテキストが選択中の組織または操作チャネルを提供します。ロールはデータの分析を代替すべきではありません。
ポリシーを一元化し、起点からデータをフィルタリングする
PHPアプリケーションには、判断を表現する一貫した場所が必要です。これは、選択したフレームワークのポリシークラス、認可サービス、または同等のコンポーネントとして具体化できます。重要なのは、コントローラーが判断を要求し、ビューだけが唯一の障壁にならないことです。
if (!$authorizer->can($actor, 'order.approve', $order, $context)) {
throw new AccessDeniedException();
}ポリシーは、判断に必要なデータだけを受け取るべきです。すなわち、アイデンティティ、操作、リソース、コンテキストです。グローバル変数を参照したり、現在のルートに暗黙的に依存したりすることは避けてください。そうすると、ルールのテストと再利用が困難になります。
一覧画面では、個別のチェックだけでは不十分です。クエリが複数組織の注文を返し、その後でUIが一部を隠した場合、すでに露出が発生しています。リポジトリまたはクエリ層でスコープを適用してください。結果を読み込む前に、認可された組織、許可された部門、または割り当てられたポートフォリオでフィルタリングします。識別子で取得するリソースでは、操作とリソースの所属の両方を確認してください。
ポリシーの一部としての状態と遷移
機微な操作は、多くの場合、状態に依存します。承認者は保留中の注文を承認できますが、キャンセル済みまたはすでに承認済みの注文は承認できません。許可された遷移を明示的にモデル化し、変更を永続化する箇所で再度検証してください。UIは案内のためにボタンを無効化できますが、有効な統制はサーバー側のポリシーです。
恒久的な例外と情報を漏らす拒否を避ける
「管理者」のような汎用ロールには、明確な境界が必要です。ある組織の管理者が、自動的にプラットフォーム管理者になるべきではありません。同様に、「この特定のレコードを編集できる」という例外には、所有者、理由、レビュー日または有効期限、トレーサビリティが必要です。それが繰り返されるなら、ビジネスルールまたはモデル属性が不足している可能性が高いです。
拒否は、機微な情報を明かさずに有用であるべきです。所属しないリソースへの直接問い合わせには通常、そのリソースが存在しない場合と区別できない応答が望まれます。すでに可視のリソースに対する操作では、内部ルール、割り当て、保護された属性を詳述せずに、権限が不足していることを示せます。
運用上の価値がある場合は、許可・拒否を問わず機微な操作を記録してください。対象は、ロール変更、エクスポート、承認、委任アクセス、設定変更です。監査には、実行者、アクション、リソース、組織またはコンテキスト、時刻、結果を含める必要があります。認証情報、トークン、不必要な個人データは記録しないでください。
プロダクトの特性として認可をテストする
認可テストは、許可される判断と拒否される判断を対象にする必要があります。最小限のテストセットには、自組織に対する権限を持つユーザー、別の組織に対する同じユーザー、権限を持たないユーザー、無効な状態のリソース、割り当ての解除や委任の終了といったコンテキスト変更を含めます。
正確な診断が得られるため、ポリシーを直接テストしてください。さらに、ルート、コントローラー、クエリ、書き込み操作が判断を適用することを確認する統合テストを追加します。最も危険な回帰は権限に関するものです。ロール、ルート、クエリ最適化の追加によって、意図せずアクセスが拡大することがあります。
- 一覧にスコープ外のリソースが含まれないことを確認します。
- 他者の識別子を知っていてもアクセスが許可されないことを確認します。
- 状態変更に対応するポリシーが必要であることを確認します。
- 権限を取り消すと、次のリクエストでその能力が無効になることを確認します。
ルールが分散したアプリケーションでモデルを導入する
システム全体を書き直す必要はありません。まず、データを変更または露出するルート、コマンド、スケジュールタスク、エクスポート箇所を棚卸しします。影響の大きい操作と、組織間で共有されるリソースを優先してください。ドメインごとにポリシーを抽出し、現行の挙動をテストでカバーしたうえで、想定以上のアクセスを許可しているルールを修正します。
その後、分散したチェックを認可サービスへの呼び出しに置き換え、スコープのフィルタリングをクエリへ移します。未使用の権限、能力が多すぎるロール、期限切れの委任、有効な例外を定期的にレビューしてください。PHPにおける権限と認可の設計が保守可能になるのは、新機能を開発する前に、誰が、どのリソースに対して、どの条件で操作し、どの証拠で確認されたかに答えられるときです。
新しいモジュールごとのチェックリスト

- ビジネス操作とそのリソースは定義されていますか。
- マトリクスは権限、スコープ、状態条件を区別していますか。
- ポリシーは、読み取り、書き込み、エクスポート、非対話プロセスに適用されていますか。
- クエリはUIに渡す前にデータをフィルタリングしていますか。
- 許可、拒否、組織間アクセスのテストはありますか。
- 機微な操作には、適切で安全な監査記録が残りますか。



