コンテンツへスキップ

承認

導入

Laravelは組み込みの認証サービスを提供することに加えて、特定のリソースに対するユーザーアクションを承認する簡単な方法も提供します。例えば、ユーザーが認証されている場合でも、アプリケーションによって管理されている特定のEloquentモデルやデータベースレコードの更新または削除を承認されていない場合があります。Laravelの承認機能は、このような種類の承認チェックを簡単に整理して管理する方法を提供します。

Laravelは、アクションを承認する2つの主要な方法を提供します。 ゲートポリシーです。ゲートとポリシーは、ルートとコントローラーのようなものと考えてください。ゲートは、承認に対するシンプルでクロージャーベースのアプローチを提供する一方、ポリシーはコントローラーのように、特定のモデルまたはリソースに関するロジックをグループ化します。このドキュメントでは、最初にゲートを説明し、次にポリシーについて説明します。

アプリケーションを構築する際に、ゲートのみを使用するか、ポリシーのみを使用するかを選択する必要はありません。ほとんどのアプリケーションは、ゲートとポリシーを組み合わせて使用することになるでしょうし、それは全く問題ありません!ゲートは、管理者ダッシュボードの表示など、モデルやリソースに関連しないアクションに最も適しています。一方、ポリシーは、特定のモデルまたはリソースに対するアクションを承認する場合に使用すべきです。

ゲート

ゲートの作成

exclamation

ゲートはLaravelの承認機能の基本を学ぶための優れた方法ですが、堅牢なLaravelアプリケーションを構築する際には、ポリシーを使用して承認ルールを整理することを検討する必要があります。

ゲートは、ユーザーが特定のアクションを実行する権限があるかどうかを判断するクロージャーです。通常、ゲートは`App\Providers\AppServiceProvider`クラスの`boot`メソッド内で、`Gate`ファサードを使用して定義されます。ゲートは常に最初の引数としてユーザーインスタンスを受け取り、関連するEloquentモデルなどの追加の引数を受け取ることもできます。

この例では、ユーザーが特定の`App\Models\Post`モデルを更新できるかどうかを判断するゲートを定義します。このゲートは、ユーザーの`id`と投稿を作成したユーザーの`user_id`を比較することでこれを実現します。

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
}

コントローラーと同様に、ゲートもクラスコールバック配列を使用して定義できます。

use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
 
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Gate::define('update-post', [PostPolicy::class, 'update']);
}

アクションの承認

ゲートを使用してアクションを承認するには、`Gate`ファサードによって提供される`allows`または`denies`メソッドを使用する必要があります。これらのメソッドに現在認証されているユーザーを渡す必要はありません。Laravelは、ユーザーをゲートクロージャーに自動的に渡します。ゲート承認メソッドは、承認が必要なアクションを実行する前に、アプリケーションのコントローラー内で呼び出すのが一般的です。

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
 
class PostController extends Controller
{
/**
* Update the given post.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if (! Gate::allows('update-post', $post)) {
abort(403);
}
 
// Update the post...
 
return redirect('/posts');
}
}

現在認証されているユーザー以外のユーザーがアクションを実行する権限があるかどうかを確認したい場合は、`Gate`ファサードの`forUser`メソッドを使用できます。

if (Gate::forUser($user)->allows('update-post', $post)) {
// The user can update the post...
}
 
if (Gate::forUser($user)->denies('update-post', $post)) {
// The user can't update the post...
}

`any`または`none`メソッドを使用して、一度に複数の操作を承認できます。

if (Gate::any(['update-post', 'delete-post'], $post)) {
// The user can update or delete the post...
}
 
if (Gate::none(['update-post', 'delete-post'], $post)) {
// The user can't update or delete the post...
}

承認または例外の発生

アクションを承認しようとして、ユーザーが特定のアクションを実行することを許可されていない場合に`Illuminate\Auth\Access\AuthorizationException`を自動的にスローしたい場合は、`Gate`ファサードの`authorize`メソッドを使用できます。`AuthorizationException`のインスタンスは、Laravelによって自動的に403 HTTPレスポンスに変換されます。

Gate::authorize('update-post', $post);
 
// The action is authorized...

追加コンテキストの提供

能力を承認するためのゲートメソッド(`allows`、`denies`、`check`、`any`、`none`、`authorize`、`can`、`cannot`)と承認Bladeディレクティブ(`@can`、`@cannot`、`@canany`)は、2番目の引数として配列を受け取ることができます。これらの配列要素は、ゲートクロージャーのパラメーターとして渡され、承認の決定を行う際の追加コンテキストに使用できます。

use App\Models\Category;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
Gate::define('create-post', function (User $user, Category $category, bool $pinned) {
if (! $user->canPublishToGroup($category->group)) {
return false;
} elseif ($pinned && ! $user->canPinPosts()) {
return false;
}
 
return true;
});
 
if (Gate::check('create-post', [$category, $pinned])) {
// The user can create the post...
}

ゲートレスポンス

これまでのところ、単純なブール値を返すゲートしか見ていません。しかし、場合によっては、エラーメッセージを含むより詳細なレスポンスを返したい場合があります。そのためには、ゲートから`Illuminate\Auth\Access\Response`を返すことができます。

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
 
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::deny('You must be an administrator.');
});

ゲートから承認レスポンスを返した場合でも、`Gate::allows`メソッドは単純なブール値を返します。ただし、`Gate::inspect`メソッドを使用して、ゲートによって返される完全な承認レスポンスを取得できます。

$response = Gate::inspect('edit-settings');
 
if ($response->allowed()) {
// The action is authorized...
} else {
echo $response->message();
}

`Gate::authorize`メソッドを使用する場合(アクションが承認されていない場合、`AuthorizationException`をスローします)、承認レスポンスによって提供されるエラーメッセージはHTTPレスポンスに伝達されます。

Gate::authorize('edit-settings');
 
// The action is authorized...

HTTPレスポンスステータスのカスタマイズ

ゲートを介してアクションが拒否された場合、`403` HTTPレスポンスが返されます。ただし、代替のHTTPステータスコードを返すことが役立つ場合があります。`Illuminate\Auth\Access\Response`クラスの`denyWithStatus`静的コンストラクターを使用して、失敗した認証チェックに対して返されるHTTPステータスコードをカスタマイズできます。

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
 
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::denyWithStatus(404);
});

`404`レスポンスを介してリソースを隠すことは、ウェブアプリケーションでは非常に一般的なパターンであるため、便宜上`denyAsNotFound`メソッドが提供されています。

use App\Models\User;
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;
 
Gate::define('edit-settings', function (User $user) {
return $user->isAdmin
? Response::allow()
: Response::denyAsNotFound();
});

ゲートチェックのインターセプト

特定のユーザーにすべての権限を付与したい場合があります。`before`メソッドを使用して、他のすべての認証チェックの前に実行されるクロージャーを定義できます。

use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
Gate::before(function (User $user, string $ability) {
if ($user->isAdministrator()) {
return true;
}
});

`before`クロージャーがNULL以外の結果を返す場合、その結果は認証チェックの結果と見なされます。

`after`メソッドを使用して、他のすべての認証チェックの後で実行されるクロージャーを定義できます。

use App\Models\User;
 
Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {
if ($user->isAdministrator()) {
return true;
}
});

after クロージャによって返される値は、ゲートまたはポリシーがnullを返す場合を除き、承認チェックの結果を上書きしません。

インライン認証

場合によっては、アクションに対応する専用のゲートを作成せずに、現在認証されているユーザーが特定のアクションを実行する権限を持っているかどうかを判断したい場合があります。Laravelでは、Gate::allowIfメソッドとGate::denyIfメソッドを使用して、このような「インライン」承認チェックを実行できます。インライン承認は、定義済みの「before」または「after」の承認フックを実行しません。

use App\Models\User;
use Illuminate\Support\Facades\Gate;
 
Gate::allowIf(fn (User $user) => $user->isAdministrator());
 
Gate::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によって作成されます。

php artisan make:policy PostPolicy

make:policyコマンドは空のポリシークラスを生成します。リソースの表示、作成、更新、削除に関連する例となるポリシーメソッドを含むクラスを生成したい場合は、コマンドの実行時に--modelオプションを指定できます。

php artisan make:policy PostPolicy --model=Post

ポリシーの登録

ポリシーの自動検出

デフォルトでは、モデルとポリシーが標準のLaravel命名規則に従っている限り、Laravelはポリシーを自動的に検出します。具体的には、ポリシーは、モデルを含むディレクトリと同じレベルか、それより上のPoliciesディレクトリに存在する必要があります。例えば、モデルをapp/Modelsディレクトリに配置し、ポリシーをapp/Policiesディレクトリに配置する場合、Laravelはapp/Models/Policies、次にapp/Policiesでポリシーをチェックします。さらに、ポリシー名はモデル名と一致し、Policyサフィックスが付いている必要があります。したがって、UserモデルはUserPolicyポリシークラスに対応します。

独自のポリシー検出ロジックを定義する場合は、Gate::guessPolicyNamesUsingメソッドを使用してカスタムポリシー検出コールバックを登録できます。通常、このメソッドはアプリケーションのAppServiceProviderbootメソッドから呼び出されます。

use Illuminate\Support\Facades\Gate;
 
Gate::guessPolicyNamesUsing(function (string $modelClass) {
// Return the name of the policy class for the given model...
});

ポリシーの手動登録

Gateファサードを使用して、アプリケーションのAppServiceProviderbootメソッド内で、ポリシーとその対応するモデルを手動で登録できます。

use App\Models\Order;
use App\Policies\OrderPolicy;
use Illuminate\Support\Facades\Gate;
 
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Gate::policy(Order::class, OrderPolicy::class);
}

ポリシーの作成

ポリシーメソッド

ポリシークラスが登録されると、承認する各アクションのメソッドを追加できます。例えば、App\Models\Userが特定のApp\Models\Postインスタンスを更新できるかどうかを判断するupdateメソッドをPostPolicyに定義してみましょう。

updateメソッドは、引数としてUserPostインスタンスを受け取り、ユーザーが指定されたPostを更新する権限があるかどうかを示すtrueまたはfalseを返す必要があります。この例では、ユーザーのidが投稿のuser_idと一致するかどうかを確認します。

<?php
 
namespace App\Policies;
 
use App\Models\Post;
use App\Models\User;
 
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*/
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}

必要に応じて、承認するさまざまなアクションに対して、ポリシーにさらにメソッドを定義できます。例えば、さまざまなPost関連のアクションを承認するためにviewメソッドやdeleteメソッドを定義できますが、ポリシーメソッドには任意の名前を付けることができます。

Artisanコンソールで--modelオプションを使用してポリシーを生成した場合、viewAnyviewcreateupdatedeleterestoreforceDeleteアクションのメソッドが既に含まれています。

lightbulb

すべてのポリシーはLaravelのサービスコンテナを介して解決されるため、ポリシーのコンストラクタに必要な依存関係を型ヒントで指定すると、それらが自動的に注入されます。

ポリシーレスポンス

これまでのところ、単純なブール値を返すポリシーメソッドしか調べていません。しかし、エラーメッセージを含むより詳細なレスポンスを返す必要がある場合があります。そのためには、ポリシーメソッドからIlluminate\Auth\Access\Responseインスタンスを返すことができます。

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
/**
* Determine if the given post can be updated by the user.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('You do not own this post.');
}

ポリシーから承認応答を返す場合、Gate::allowsメソッドは依然として単純なブール値を返しますが、Gate::inspectメソッドを使用して、ゲートによって返された完全な承認応答を取得できます。

use Illuminate\Support\Facades\Gate;
 
$response = Gate::inspect('update', $post);
 
if ($response->allowed()) {
// The action is authorized...
} else {
echo $response->message();
}

`Gate::authorize`メソッドを使用する場合(アクションが承認されていない場合、`AuthorizationException`をスローします)、承認レスポンスによって提供されるエラーメッセージはHTTPレスポンスに伝達されます。

Gate::authorize('update', $post);
 
// The action is authorized...

HTTPレスポンスステータスのカスタマイズ

ポリシーメソッドによってアクションが拒否されると、403 HTTPレスポンスが返されますが、代替のHTTPステータスコードを返す方が便利な場合があります。Illuminate\Auth\Access\ResponseクラスのdenyWithStatus静的コンストラクタを使用して、失敗した承認チェックに対して返されるHTTPステータスコードをカスタマイズできます。

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
/**
* Determine if the given post can be updated by the user.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyWithStatus(404);
}

`404`レスポンスを介してリソースを隠すことは、ウェブアプリケーションでは非常に一般的なパターンであるため、便宜上`denyAsNotFound`メソッドが提供されています。

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
 
/**
* Determine if the given post can be updated by the user.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyAsNotFound();
}

モデルを使用しないメソッド

一部のポリシーメソッドは、現在認証されているユーザーのインスタンスのみを受け取ります。これは、createアクションを承認する場合に最も一般的です。例えば、ブログを作成する場合、ユーザーが投稿を作成できるかどうかを判断したい場合があります。このような場合、ポリシーメソッドはユーザーインスタンスのみを受け取る必要があります。

/**
* Determine if the given user can create posts.
*/
public function create(User $user): bool
{
return $user->role == 'writer';
}

ゲストユーザー

デフォルトでは、すべてのゲートとポリシーは、着信HTTPリクエストが認証済みユーザーによって開始されていない場合、自動的にfalseを返します。ただし、「optional」型ヒントを宣言するか、ユーザー引数定義にnullのデフォルト値を指定することで、これらの承認チェックをゲートとポリシーに渡すことができます。

<?php
 
namespace App\Policies;
 
use App\Models\Post;
use App\Models\User;
 
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*/
public function update(?User $user, Post $post): bool
{
return $user?->id === $post->user_id;
}
}

ポリシーフィルター

特定のユーザーに対して、特定のポリシー内のすべてのアクションを承認したい場合があります。これを実現するには、ポリシーにbeforeメソッドを定義します。beforeメソッドは、ポリシーの他のメソッドの前に実行され、目的のポリシーメソッドが実際に呼び出される前にアクションを承認する機会が得られます。この機能は、アプリケーション管理者が任意のアクションを実行することを承認する場合に最もよく使用されます。

use App\Models\User;
 
/**
* Perform pre-authorization checks.
*/
public function before(User $user, string $ability): bool|null
{
if ($user->isAdministrator()) {
return true;
}
 
return null;
}

特定の種類のユーザーのすべての承認チェックを拒否する場合は、beforeメソッドからfalseを返すことができます。nullが返された場合、承認チェックはポリシーメソッドに渡されます。

exclamation

ポリシークラスのbeforeメソッドは、クラスがチェックされている能力の名前と一致する名前のメソッドを含まない場合は呼び出されません。

ポリシーを使用したアクションの承認

ユーザーモデル経由

Laravelアプリケーションに含まれるApp\Models\Userモデルには、アクションを承認するための2つの便利なメソッド(cancannot)が含まれています。cancannotメソッドは、承認するアクションの名前と関連するモデルを受け取ります。例えば、ユーザーが特定のApp\Models\Postモデルを更新する権限があるかどうかを判断してみましょう。通常、これはコントローラーメソッド内で行われます。

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
/**
* Update the given post.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if ($request->user()->cannot('update', $post)) {
abort(403);
}
 
// Update the post...
 
return redirect('/posts');
}
}

指定されたモデルに対してポリシーが登録されている場合、canメソッドは適切なポリシーを自動的に呼び出し、ブール値の結果を返します。モデルに対してポリシーが登録されていない場合、canメソッドは指定されたアクション名と一致するクロージャベースのゲートを呼び出そうとします。

モデルを必要としないアクション

一部のアクションは、モデルインスタンスを必要としないcreateのようなポリシーメソッドに対応している場合があります。このような場合、canメソッドにクラス名を渡すことができます。クラス名は、アクションを承認する際に使用するポリシーを決定するために使用されます。

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
/**
* Create a post.
*/
public function store(Request $request): RedirectResponse
{
if ($request->user()->cannot('create', Post::class)) {
abort(403);
}
 
// Create the post...
 
return redirect('/posts');
}
}

Gateファサードによる方法

App\Models\Userモデルに提供される便利なメソッドに加えて、常にGateファサードのauthorizeメソッドを使用してアクションを承認できます。

canメソッドと同様に、このメソッドは承認するアクションの名前と関連するモデルを受け取ります。アクションが承認されていない場合、authorizeメソッドはIlluminate\Auth\Access\AuthorizationException例外をスローします。Laravelの例外ハンドラーは、これを自動的に403ステータスコードのHTTPレスポンスに変換します。

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
 
class PostController extends Controller
{
/**
* Update the given blog post.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post): RedirectResponse
{
Gate::authorize('update', $post);
 
// The current user can update the blog post...
 
return redirect('/posts');
}
}

モデルを必要としないアクション

前述のように、createなどの一部のポリシーメソッドはモデルインスタンスを必要としません。このような場合、クラス名をauthorizeメソッドに渡す必要があります。クラス名は、アクションを承認する際に使用するポリシーを決定するために使用されます。

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
 
/**
* Create a new blog post.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request): RedirectResponse
{
Gate::authorize('create', Post::class);
 
// The current user can create blog posts...
 
return redirect('/posts');
}

ミドルウェア経由

Laravelには、着信リクエストがルートやコントローラーに到達する前にアクションを承認できるミドルウェアが含まれています。デフォルトでは、Illuminate\Auth\Middleware\Authorizeミドルウェアは、Laravelによって自動的に登録されるcanミドルウェアエイリアスを使用してルートにアタッチできます。ユーザーが投稿を更新できることを承認するためにcanミドルウェアを使用する例を見てみましょう。

use App\Models\Post;
 
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');

この例では、canミドルウェアに2つの引数を渡しています。1つ目は、承認するアクションの名前、2つ目はポリシーメソッドに渡すルートパラメーターです。ここでは暗黙的なモデルバインディングを使用しているため、App\Models\Postモデルがポリシーメソッドに渡されます。ユーザーが指定されたアクションを実行する権限がない場合、ミドルウェアによって403ステータスコードのHTTPレスポンスが返されます。

便宜上、canメソッドを使用してルートにcanミドルウェアをアタッチすることもできます。

use App\Models\Post;
 
Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->can('update', 'post');

モデルを必要としないアクション

同様に、createなどの一部のポリシーメソッドはモデルインスタンスを必要としません。このような場合、ミドルウェアにクラス名を渡すことができます。クラス名は、アクションを承認する際に使用するポリシーを決定するために使用されます。

Route::post('/post', function () {
// The current user may create posts...
})->middleware('can:create,App\Models\Post');

文字列ミドルウェア定義内にクラス名を完全に指定すると煩雑になるため、canメソッドを使用してルートにcanミドルウェアをアタッチすることを選択できます。

use App\Models\Post;
 
Route::post('/post', function () {
// The current user may create posts...
})->can('create', Post::class);

Bladeテンプレート経由

Bladeテンプレートを作成する際には、ユーザーが特定のアクションを実行する権限がある場合にのみページの一部を表示したい場合があります。例えば、ユーザーが投稿を実際に更新できる場合にのみ、ブログ投稿の更新フォームを表示したい場合があります。このような場合、@canディレクティブと@cannotディレクティブを使用できます。

@can('update', $post)
<!-- The current user can update the post... -->
@elsecan('create', App\Models\Post::class)
<!-- The current user can create new posts... -->
@else
<!-- ... -->
@endcan
 
@cannot('update', $post)
<!-- The current user cannot update the post... -->
@elsecannot('create', App\Models\Post::class)
<!-- The current user cannot create new posts... -->
@endcannot

これらのディレクティブは、@ifステートメントと@unlessステートメントを作成するための便利なショートカットです。上記の@canステートメントと@cannotステートメントは、次のステートメントと同等です。

@if (Auth::user()->can('update', $post))
<!-- The current user can update the post... -->
@endif
 
@unless (Auth::user()->can('update', $post))
<!-- The current user cannot update the post... -->
@endunless

指定されたアクションの配列から、ユーザーが任意のアクションを実行する権限があるかどうかを判断することもできます。これを実現するには、@cananyディレクティブを使用します。

@canany(['update', 'view', 'delete'], $post)
<!-- The current user can update, view, or delete the post... -->
@elsecanany(['create'], \App\Models\Post::class)
<!-- The current user can create a post... -->
@endcanany

モデルを必要としないアクション

他のほとんどの承認メソッドと同様に、アクションがモデルインスタンスを必要としない場合、クラス名を@canディレクティブと@cannotディレクティブに渡すことができます。

@can('create', App\Models\Post::class)
<!-- The current user can create posts... -->
@endcan
 
@cannot('create', App\Models\Post::class)
<!-- The current user can't create posts... -->
@endcannot

追加コンテキストの提供

ポリシーを使用してアクションを承認する際、さまざまな承認関数およびヘルパーの第2引数として配列を渡すことができます。配列の最初の要素は、どのポリシーを呼び出すかを決定するために使用され、残りの配列要素はポリシーメソッドのパラメーターとして渡され、承認決定を行う際の追加のコンテキストとして使用できます。たとえば、追加の$categoryパラメーターを含む次のPostPolicyメソッド定義を考えてみましょう。

/**
* Determine if the given post can be updated by the user.
*/
public function update(User $user, Post $post, int $category): bool
{
return $user->id === $post->user_id &&
$user->canUpdateCategory($category);
}

認証済みユーザーが特定の投稿を更新できるかどうかを判断しようとすると、次のようにこのポリシーメソッドを呼び出すことができます。

/**
* Update the given blog post.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post): RedirectResponse
{
Gate::authorize('update', [$post, $request->category]);
 
// The current user can update the blog post...
 
return redirect('/posts');
}

認証とInertia

承認は常にサーバーで処理する必要がありますが、フロントエンドアプリケーションに承認データを用意してアプリケーションのUIを適切にレンダリングすることが便利な場合があります。Laravelは、Inertia対応のフロントエンドに承認情報を公開するための必須の規約を定義していません。

ただし、LaravelのInertiaベースのスターターキットのいずれかを使用している場合、アプリケーションには既にHandleInertiaRequestsミドルウェアが含まれています。このミドルウェアのshareメソッド内で、アプリケーションのすべてのInertiaページに提供される共有データを返すことができます。この共有データは、ユーザーの承認情報を定義するための便利な場所として機能します。

<?php
 
namespace App\Http\Middleware;
 
use App\Models\Post;
use Illuminate\Http\Request;
use Inertia\Middleware;
 
class HandleInertiaRequests extends Middleware
{
// ...
 
/**
* Define the props that are shared by default.
*
* @return array<string, mixed>
*/
public function share(Request $request)
{
return [
...parent::share($request),
'auth' => [
'user' => $request->user(),
'permissions' => [
'post' => [
'create' => $request->user()->can('create', Post::class),
],
],
],
];
}
}