認可
イントロダクション
Laravelは、組み込みの認証サービスを提供しているだけでなく、特定のリソースに対するユーザーアクションを認可する簡単な方法も提供しています。たとえば、ユーザーが認証されていても、アプリケーションが管理する特定のEloquentモデルやデータベースレコードを更新または削除する権限がない場合があります。Laravelの認可機能は、これらのタイプの認可チェックを管理するための簡単で整理された方法を提供します。
Laravelはアクションを認可する主要な方法をゲートとポリシーの2つ提供しています。ゲートとポリシーをルートとコントローラのように考えてください。ゲートは認可へのシンプルでクロージャベースのアプローチを提供し、ポリシーはコントローラのように、特定のモデルまたはリソースに関するロジックをグループ化します。このドキュメントでは、まずゲートについて説明し、次にポリシーについて説明します。
アプリケーションを構築する際に、ゲートのみを使用するか、ポリシーのみを使用するかを選択する必要はありません。ほとんどのアプリケーションでは、ゲートとポリシーが混在している可能性が最も高く、それはまったく問題ありません。ゲートは、管理者ダッシュボードの表示など、どのモデルやリソースにも関連しないアクションに最も適しています。対照的に、ポリシーは、特定のモデルまたはリソースに対するアクションを認可する場合に使用する必要があります。
ゲート
ゲートの記述
ゲートはLaravelの認可機能の基本を学ぶのに最適な方法です。しかし、堅牢なLaravelアプリケーションを構築する場合は、認可ルールを体系化するためにポリシーの使用を検討する必要があります。
ゲートは、ユーザーが特定のアクションを実行する権限を持っているかどうかを判断する単なるクロージャです。通常、ゲートはGateファサードを使用して、App\Providers\AppServiceProviderクラスのbootメソッド内で定義します。ゲートは常に最初の引数としてユーザーインスタンスを受け取り、オプションで関連するEloquentモデルなどの追加の引数を受け取ることができます。
この例では、ユーザーが特定のApp\Models\Postモデルを更新できるかどうかを判断するゲートを定義します。ゲートは、ユーザーのidを投稿を作成したユーザーのuser_idと比較することによって、これを実現します。
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Support\Facades\Gate; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 Gate::define('update-post', function (User $user, Post $post) {11 return $user->id === $post->user_id;12 });13}
コントローラと同様に、ゲートもクラスコールバック配列を使用して定義できます。
1use App\Policies\PostPolicy; 2use Illuminate\Support\Facades\Gate; 3 4/** 5 * Bootstrap any application services. 6 */ 7public function boot(): void 8{ 9 Gate::define('update-post', [PostPolicy::class, 'update']);10}
アクションの認可
ゲートを使用してアクションを認可するには、Gateファサードが提供するallowsまたはdeniesメソッドを使用する必要があります。これらのメソッドに現在認証されているユーザーを渡す必要はないことに注意してください。Laravelはユーザーをゲートクロージャへ渡すのを自動的に処理します。認可を必要とするアクションを実行する前に、アプリケーションのコントローラ内でゲート認可メソッドを呼び出すのが一般的です。
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9use Illuminate\Support\Facades\Gate;10 11class PostController extends Controller12{13 /**14 * Update the given post.15 */16 public function update(Request $request, Post $post): RedirectResponse17 {18 if (! Gate::allows('update-post', $post)) {19 abort(403);20 }21 22 // Update the post...23 24 return redirect('/posts');25 }26}
現在認証されているユーザー以外のユーザーがアクションを実行する権限があるかどうかを判断したい場合は、GateファサードのforUserメソッドを使用します。
1if (Gate::forUser($user)->allows('update-post', $post)) {2 // The user can update the post...3}4 5if (Gate::forUser($user)->denies('update-post', $post)) {6 // The user can't update the post...7}
anyまたはnoneメソッドを使用して、一度に複数のアクションを認可できます。
1if (Gate::any(['update-post', 'delete-post'], $post)) {2 // The user can update or delete the post...3}4 5if (Gate::none(['update-post', 'delete-post'], $post)) {6 // The user can't update or delete the post...7}
認可または例外のスロー
アクションの認可を試み、ユーザーが特定のアクションの実行を許可されていない場合に、自動的にIlluminate\Auth\Access\AuthorizationExceptionをスローしたい場合は、Gateファサードのauthorizeメソッドを使用できます。AuthorizationExceptionのインスタンスは、Laravelによって自動的に403 HTTPレスポンスに変換されます。
1Gate::authorize('update-post', $post);2 3// The action is authorized...
追加コンテキストの提供
認可機能(allows、denies、check、any、none、authorize、can、cannot)のゲートメソッドと、認可Bladeディレクティブ(@can、@cannot、@canany)は、2番目の引数として配列を受け取ることができます。これらの配列要素は、ゲートクロージャへパラメータとして渡され、認可を決定する際に追加のコンテキストとして使用できます。
1use App\Models\Category; 2use App\Models\User; 3use Illuminate\Support\Facades\Gate; 4 5Gate::define('create-post', function (User $user, Category $category, bool $pinned) { 6 if (! $user->canPublishToGroup($category->group)) { 7 return false; 8 } elseif ($pinned && ! $user->canPinPosts()) { 9 return false;10 }11 12 return true;13});14 15if (Gate::check('create-post', [$category, $pinned])) {16 // The user can create the post...17}
ゲートのレスポンス
これまで、単純な論理値を返すゲートのみを調べてきました。ただし、エラーメッセージなどのより詳細なレスポンスを返したい場合もあります。そうするには、ゲートからIlluminate\Auth\Access\Responseを返します。
1use App\Models\User;2use Illuminate\Auth\Access\Response;3use Illuminate\Support\Facades\Gate;4 5Gate::define('edit-settings', function (User $user) {6 return $user->isAdmin7 ? Response::allow()8 : Response::deny('You must be an administrator.');9});
ゲートから認可レスポンスを返した場合でも、Gate::allowsメソッドは単純な論理値を返します。ただし、Gate::inspectメソッドを使用して、ゲートによって返された完全な認可レスポンスを取得できます。
1$response = Gate::inspect('edit-settings');2 3if ($response->allowed()) {4 // The action is authorized...5} else {6 echo $response->message();7}
Gate::authorizeメソッドを使用すると、アクションが認可されていない場合にAuthorizationExceptionがスローされ、認可レスポンスによって提供されるエラーメッセージがHTTPレスポンスに伝播されます。
1Gate::authorize('edit-settings');2 3// The action is authorized...
HTTPレスポンスステータスのカスタマイズ
ゲートを介してアクションが拒否されると、403 HTTPレスポンスが返されます。ただし、別のHTTPステータスコードを返すと便利な場合があります。Illuminate\Auth\Access\ResponseクラスのdenyWithStatus静的コンストラクタを使用して、失敗した認可チェックに対して返されるHTTPステータスコードをカスタマイズできます。
1use App\Models\User;2use Illuminate\Auth\Access\Response;3use Illuminate\Support\Facades\Gate;4 5Gate::define('edit-settings', function (User $user) {6 return $user->isAdmin7 ? Response::allow()8 : Response::denyWithStatus(404);9});
404レスポンスでリソースを隠すのはWebアプリケーションで非常に一般的なパターンであるため、denyAsNotFoundメソッドが便宜のために提供されています。
1use App\Models\User;2use Illuminate\Auth\Access\Response;3use Illuminate\Support\Facades\Gate;4 5Gate::define('edit-settings', function (User $user) {6 return $user->isAdmin7 ? Response::allow()8 : Response::denyAsNotFound();9});
ゲートチェックのインターセプト
特定のユーザーにすべての権限を付与したい場合があります。beforeメソッドを使用して、他のすべての認可チェックの前に実行されるクロージャを定義できます。
1use App\Models\User;2use Illuminate\Support\Facades\Gate;3 4Gate::before(function (User $user, string $ability) {5 if ($user->isAdministrator()) {6 return true;7 }8});
beforeクロージャがnull以外の結果を返した場合、その結果が認可チェックの結果と見なされます。
afterメソッドを使用して、他のすべての認可チェックの後に実行されるクロージャを定義できます。
1use App\Models\User;2 3Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {4 if ($user->isAdministrator()) {5 return true;6 }7});
afterクロージャによって返される値は、ゲートまたはポリシーがnullを返さない限り、認可チェックの結果をオーバーライドしません。
インライン認可
アクションに対応する専用のゲートを記述せずに、現在認証されているユーザーが特定のアクションを実行する権限があるかどうかを判断したい場合があります。Laravelでは、Gate::allowIfおよびGate::denyIfメソッドを介して、これらのタイプの「インライン」認可チェックを実行できます。インライン認可は、定義済みの「before」または「after」認可フックを実行しません。
1use App\Models\User;2use Illuminate\Support\Facades\Gate;3 4Gate::allowIf(fn (User $user) => $user->isAdministrator());5 6Gate::denyIf(fn (User $user) => $user->banned());
アクションが認可されていない場合、または現在認証されているユーザーがいない場合、Laravelは自動的にIlluminate\Auth\Access\AuthorizationException例外をスローします。AuthorizationExceptionのインスタンスは、Laravelの例外ハンドラによって自動的に403 HTTPレスポンスに変換されます。
ポリシーの作成
ポリシーの生成
ポリシーは、特定のモデルまたはリソースに関する認可ロジックを体系化するクラスです。たとえば、アプリケーションがブログである場合、投稿の作成や更新などのユーザーアクションを認可するために、App\Models\Postモデルと、対応するApp\Policies\PostPolicyを用意できます。
ポリシーはmake:policy Artisanコマンドを使用して生成できます。生成されたポリシーはapp/Policiesディレクトリに配置されます。このディレクトリがアプリケーションに存在しない場合、Laravelはそれを作成します。
1php artisan make:policy PostPolicy
make:policyコマンドは、空のポリシークラスを生成します。リソースの表示、作成、更新、削除に関連するポリシーメソッドの例を含むクラスを生成したい場合は、コマンドの実行時に--modelオプションを指定します。
1php artisan make:policy PostPolicy --model=Post
ポリシーの登録
ポリシーの発見
デフォルトでは、モデルとポリシーがLaravelの標準的な命名規則に従っている限り、Laravelはポリシーを自動的に検出します。具体的には、ポリシーはモデルを含むディレクトリか、それより上の階層にあるPoliciesディレクトリに存在している必要があります。したがって、たとえば、モデルをapp/Modelsディレクトリに配置し、ポリシーをapp/Policiesディレクトリに配置することができます。この場合、Laravelは最初にapp/Models/Policies、次にapp/Policiesでポリシーをチェックします。さらに、ポリシー名はモデル名と一致し、Policyサフィックスが付いている必要があります。したがって、UserモデルはUserPolicyポリシークラスに対応します。
独自のポリシー検出ロジックを定義したい場合は、Gate::guessPolicyNamesUsingメソッドを使用してカスタムポリシー検出コールバックを登録できます。通常、このメソッドはアプリケーションのAppServiceProviderのbootメソッドから呼び出す必要があります。
1use Illuminate\Support\Facades\Gate;2 3Gate::guessPolicyNamesUsing(function (string $modelClass) {4 // Return the name of the policy class for the given model...5});
ポリシーの手動登録
Gateファサードを使用して、アプリケーションのAppServiceProviderのbootメソッド内で、ポリシーとそれに対応するモデルを手動で登録できます。
1use App\Models\Order; 2use App\Policies\OrderPolicy; 3use Illuminate\Support\Facades\Gate; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 Gate::policy(Order::class, OrderPolicy::class);11}
ポリシーの記述
ポリシ-メソッド
ポリシークラスが登録されると、それが認可する各アクションのメソッドを追加できます。たとえば、PostPolicyで特定のApp\Models\Userが特定のApp\Models\Postインスタンスを更新できるかどうかを決定するupdateメソッドを定義してみましょう。
updateメソッドは、UserインスタンスとPostインスタンスを引数として受け取り、ユーザーが特定のPostを更新する権限があるかどうかを示すtrueまたはfalseを返す必要があります。したがって、この例では、ユーザーのidが投稿のuser_idと一致することを確認します。
1<?php 2 3namespace App\Policies; 4 5use App\Models\Post; 6use App\Models\User; 7 8class PostPolicy 9{10 /**11 * Determine if the given post can be updated by the user.12 */13 public function update(User $user, Post $post): bool14 {15 return $user->id === $post->user_id;16 }17}
認可するさまざまなアクションに応じて、必要に応じてポリシーにメソッドを追加し定義を続けられます。たとえば、さまざまなPost関連のアクションを認可するためにviewやdeleteメソッドを定義できますが、ポリシーメソッドには好きな名前を自由に付けられることを忘れないでください。
Artisanコンソールでポリシーを生成するときに--modelオプションを使用した場合、viewAny、view、create、update、delete、restore、forceDeleteアクションのメソッドがすでに含まれています。
すべてのポリシーはLaravelのサービスコンテナを介して解決されるため、ポリシーのコンストラクタで必要な依存関係をタイプヒントで指定すれば、自動的に注入されます。
ポリシーのレスポンス
これまで、単純な論理値を返すポリシーメソッドのみを調べてきました。ただし、エラーメッセージなどのより詳細なレスポンスを返したい場合もあります。そうするには、ポリシーメソッドからIlluminate\Auth\Access\Responseインスタンスを返します。
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Auth\Access\Response; 4 5/** 6 * Determine if the given post can be updated by the user. 7 */ 8public function update(User $user, Post $post): Response 9{10 return $user->id === $post->user_id11 ? Response::allow()12 : Response::deny('You do not own this post.');13}
ポリシーから認可レスポンスを返した場合でも、Gate::allowsメソッドは単純な論理値を返します。ただし、Gate::inspectメソッドを使用して、ゲートによって返された完全な認可レスポンスを取得できます。
1use Illuminate\Support\Facades\Gate;2 3$response = Gate::inspect('update', $post);4 5if ($response->allowed()) {6 // The action is authorized...7} else {8 echo $response->message();9}
Gate::authorizeメソッドを使用すると、アクションが認可されていない場合にAuthorizationExceptionがスローされ、認可レスポンスによって提供されるエラーメッセージがHTTPレスポンスに伝播されます。
1Gate::authorize('update', $post);2 3// The action is authorized...
HTTPレスポンスステータスのカスタマイズ
ポリシーメソッドを介してアクションが拒否されると、403 HTTPレスポンスが返されます。ただし、別のHTTPステータスコードを返すと便利な場合があります。Illuminate\Auth\Access\ResponseクラスのdenyWithStatus静的コンストラクタを使用して、失敗した認可チェックに対して返されるHTTPステータスコードをカスタマイズできます。
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Auth\Access\Response; 4 5/** 6 * Determine if the given post can be updated by the user. 7 */ 8public function update(User $user, Post $post): Response 9{10 return $user->id === $post->user_id11 ? Response::allow()12 : Response::denyWithStatus(404);13}
404レスポンスでリソースを隠すのはWebアプリケーションで非常に一般的なパターンであるため、denyAsNotFoundメソッドが便宜のために提供されています。
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Auth\Access\Response; 4 5/** 6 * Determine if the given post can be updated by the user. 7 */ 8public function update(User $user, Post $post): Response 9{10 return $user->id === $post->user_id11 ? Response::allow()12 : Response::denyAsNotFound();13}
モデルなしのメソッド
一部のポリシーメソッドは、現在認証されているユーザーのインスタンスのみを受け取ります。この状況は、createアクションを認可する場合に最も一般的です。たとえば、ブログを作成している場合、ユーザーが投稿を作成する権限を持っているかどうかを判断したい場合があります。このような状況では、ポリシーメソッドはユーザーインスタンスのみを受け取ることを期待する必要があります。
1/**2 * Determine if the given user can create posts.3 */4public function create(User $user): bool5{6 return $user->role == 'writer';7}
ゲストユーザー
デフォルトでは、受信HTTPリクエストが認証済みユーザーによって開始されなかった場合、すべてのゲートとポリシーは自動的にfalseを返します。ただし、「オプショナル」なタイプヒントを宣言するか、ユーザー引数定義にnullのデフォルト値を指定することで、これらの認可チェックをゲートとポリシーに通過させることができます。
1<?php 2 3namespace App\Policies; 4 5use App\Models\Post; 6use App\Models\User; 7 8class PostPolicy 9{10 /**11 * Determine if the given post can be updated by the user.12 */13 public function update(?User $user, Post $post): bool14 {15 return $user?->id === $post->user_id;16 }17}
ポリシーフィルタ
特定のユーザーに対して、特定のポリシー内のすべてのアクションを認可したい場合があります。これを実現するには、ポリシーにbeforeメソッドを定義します。beforeメソッドは、ポリシーの他のどのメソッドよりも先に実行され、意図したポリシーメソッドが実際に呼び出される前にアクションを認可する機会を提供します。この機能は、アプリケーション管理者が任意のアクションを実行できるように認可するために最も一般的に使用されます。
1use App\Models\User; 2 3/** 4 * Perform pre-authorization checks. 5 */ 6public function before(User $user, string $ability): bool|null 7{ 8 if ($user->isAdministrator()) { 9 return true;10 }11 12 return null;13}
特定の種類のユーザーに対するすべての認可チェックを拒否したい場合は、beforeメソッドからfalseを返すことができます。nullが返された場合、認可チェックはポリシーメソッドにフォールスルーします。
ポリシークラスのbeforeメソッドは、チェック対象のアビリティ名と一致する名前のメソッドがクラスに含まれていない場合は呼び出されません。
ポリシーを使用したアクションの認可
Userモデル経由
Laravelアプリケーションに含まれているApp\Models\Userモデルには、アクションを認可するための2つの便利なメソッド、canとcannotがあります。canとcannotメソッドは、認可したいアクションの名前と関連するモデルを受け取ります。たとえば、ユーザーが特定のApp\Models\Postモデルを更新する権限があるかどうかを判断してみましょう。通常、これはコントローラメソッド内で行います。
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9 10class PostController extends Controller11{12 /**13 * Update the given post.14 */15 public function update(Request $request, Post $post): RedirectResponse16 {17 if ($request->user()->cannot('update', $post)) {18 abort(403);19 }20 21 // Update the post...22 23 return redirect('/posts');24 }25}
特定のモデルに対してポリシーが登録されている場合、canメソッドは自動的に適切なポリシーを呼び出し、論理値の結果を返します。モデルにポリシーが登録されていない場合、canメソッドは、指定されたアクション名に一致するクロージャベースのゲートを呼び出そうとします。
モデルを必要としないアクション
createのようなポリシーメソッドに対応するアクションの中には、モデルインスタンスを必要としないものがあることを覚えておいてください。このような状況では、canメソッドにクラス名を渡すことができます。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9 10class PostController extends Controller11{12 /**13 * Create a post.14 */15 public function store(Request $request): RedirectResponse16 {17 if ($request->user()->cannot('create', Post::class)) {18 abort(403);19 }20 21 // Create the post...22 23 return redirect('/posts');24 }25}
Gateファサード経由
App\Models\Userモデルに提供されている便利なメソッドに加えて、Gateファサードのauthorizeメソッドを介していつでもアクションを認可できます。
canメソッドと同様に、このメソッドは認可したいアクションの名前と関連モデルを受け入れます。アクションが認可されていない場合、authorizeメソッドはIlluminate\Auth\Access\AuthorizationException例外をスローし、Laravel例外ハンドラはそれを自動的に403ステータスコードのHTTPレスポンスに変換します。
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9use Illuminate\Support\Facades\Gate;10 11class PostController extends Controller12{13 /**14 * Update the given blog post.15 *16 * @throws \Illuminate\Auth\Access\AuthorizationException17 */18 public function update(Request $request, Post $post): RedirectResponse19 {20 Gate::authorize('update', $post);21 22 // The current user can update the blog post...23 24 return redirect('/posts');25 }26}
モデルを必要としないアクション
前述のように、createのような一部のポリシーメソッドはモデルインスタンスを必要としません。このような状況では、authorizeメソッドにクラス名を渡す必要があります。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。
1use App\Models\Post; 2use Illuminate\Http\RedirectResponse; 3use Illuminate\Http\Request; 4use Illuminate\Support\Facades\Gate; 5 6/** 7 * Create a new blog post. 8 * 9 * @throws \Illuminate\Auth\Access\AuthorizationException10 */11public function create(Request $request): RedirectResponse12{13 Gate::authorize('create', Post::class);14 15 // The current user can create blog posts...16 17 return redirect('/posts');18}
ミドルウェア経由
Laravelには、受信リクエストがルートやコントローラに到達する前にアクションを認可できるミドルウェアが含まれています。デフォルトで、Illuminate\Auth\Middleware\Authorizeミドルウェアは、Laravelによって自動的に登録されるcan ミドルウェアエイリアスを使用してルートにアタッチできます。ユーザーが投稿を更新できることを認可するためにcanミドルウェアを使用する例を見てみましょう。
1use App\Models\Post;2 3Route::put('/post/{post}', function (Post $post) {4 // The current user may update the post...5})->middleware('can:update,post');
この例では、canミドルウェアに2つの引数を渡しています。1つ目は認可したいアクションの名前で、2つ目はポリシーメソッドに渡したいルートパラメータです。この場合、暗黙のモデル結合を使用しているため、App\Models\Postモデルがポリシーメソッドに渡されます。ユーザーが指定されたアクションを実行する権限を持っていない場合、ミドルウェアによって403ステータスコードのHTTPレスポンスが返されます。
便宜上、canメソッドを使用してルートにcanミドルウェアをアタッチすることもできます。
1use App\Models\Post;2 3Route::put('/post/{post}', function (Post $post) {4 // The current user may update the post...5})->can('update', 'post');
モデルを必要としないアクション
繰り返しになりますが、createのような一部のポリシーメソッドはモデルインスタンスを必要としません。このような状況では、ミドルウェアにクラス名を渡すことができます。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。
1Route::post('/post', function () {2 // The current user may create posts...3})->middleware('can:create,App\Models\Post');
文字列のミドルウェア定義内で完全なクラス名を指定するのは面倒になることがあります。そのため、canメソッドを使用してルートにcanミドルウェアをアタッチすることを選択できます。
1use App\Models\Post;2 3Route::post('/post', function () {4 // The current user may create posts...5})->can('create', Post::class);
Bladeテンプレート経由
Bladeテンプレートを作成するとき、ユーザーが特定のアクションを実行する権限を持っている場合にのみページの一部を表示したい場合があります。たとえば、ユーザーが実際に投稿を更新できる場合にのみ、ブログ投稿の更新フォームを表示したい場合があります。このような状況では、@canおよび@cannotディレクティブを使用できます。
1@can('update', $post) 2 <!-- The current user can update the post... --> 3@elsecan('create', App\Models\Post::class) 4 <!-- The current user can create new posts... --> 5@else 6 <!-- ... --> 7@endcan 8 9@cannot('update', $post)10 <!-- The current user cannot update the post... -->11@elsecannot('create', App\Models\Post::class)12 <!-- The current user cannot create new posts... -->13@endcannot
これらのディレクティブは、@ifおよび@unlessステートメントを記述するための便利なショートカットです。上記の@canおよび@cannotステートメントは、次のステートメントと同じです。
1@if (Auth::user()->can('update', $post))2 <!-- The current user can update the post... -->3@endif4 5@unless (Auth::user()->can('update', $post))6 <!-- The current user cannot update the post... -->7@endunless
特定の配列のアクションの中から、ユーザーがどのアクションを実行する権限があるかを判断することもできます。これを実現するには、@cananyディレクティブを使用します。
1@canany(['update', 'view', 'delete'], $post)2 <!-- The current user can update, view, or delete the post... -->3@elsecanany(['create'], \App\Models\Post::class)4 <!-- The current user can create a post... -->5@endcanany
モデルを必要としないアクション
他のほとんどの認可メソッドと同様に、アクションがモデルインスタンスを必要としない場合は、@canおよび@cannotディレクティブにクラス名を渡すことができます。
1@can('create', App\Models\Post::class)2 <!-- The current user can create posts... -->3@endcan4 5@cannot('create', App\Models\Post::class)6 <!-- The current user can't create posts... -->7@endcannot
追加コンテキストの提供
ポリシーを使用してアクションを認可する場合、さまざまな認可関数やヘルパの2番目の引数として配列を渡すことができます。配列の最初の要素は、どのポリシーを呼び出すかを決定するために使用され、残りの配列要素はポリシーメソッドにパラメータとして渡され、認可の決定を行う際に追加のコンテキストとして使用できます。たとえば、追加の$categoryパラメータを含む次のPostPolicyメソッド定義を考えてみましょう。
1/**2 * Determine if the given post can be updated by the user.3 */4public function update(User $user, Post $post, int $category): bool5{6 return $user->id === $post->user_id &&7 $user->canUpdateCategory($category);8}
認証済みユーザーが特定の投稿を更新できるかどうかを判断しようとするとき、このポリシーメソッドを次のように呼び出すことができます。
1/** 2 * Update the given blog post. 3 * 4 * @throws \Illuminate\Auth\Access\AuthorizationException 5 */ 6public function update(Request $request, Post $post): RedirectResponse 7{ 8 Gate::authorize('update', [$post, $request->category]); 9 10 // The current user can update the blog post...11 12 return redirect('/posts');13}
認可とInertia
認可は常にサーバ側で処理する必要がありますが、アプリケーションのUIを適切にレンダリングするために、フロントエンドアプリケーションに認可データを提供すると便利な場合があります。Laravelは、Inertiaを利用したフロントエンドに認可情報を公開するための必須の規約を定義していません。
しかし、LaravelのInertiaベースのスターターキットのいずれかを使用している場合、アプリケーションにはすでにHandleInertiaRequestsミドルウェアが含まれています。このミドルウェアのshareメソッド内で、アプリケーションのすべてのInertiaページに提供される共有データを返すことができます。この共有データは、ユーザーの認可情報を定義するのに便利な場所として役立ちます。
1<?php 2 3namespace App\Http\Middleware; 4 5use App\Models\Post; 6use Illuminate\Http\Request; 7use Inertia\Middleware; 8 9class HandleInertiaRequests extends Middleware10{11 // ...12 13 /**14 * Define the props that are shared by default.15 *16 * @return array<string, mixed>17 */18 public function share(Request $request)19 {20 return [21 ...parent::share($request),22 'auth' => [23 'user' => $request->user(),24 'permissions' => [25 'post' => [26 'create' => $request->user()->can('create', Post::class),27 ],28 ],29 ],30 ];31 }32}