イントロダクションIntroduction
組み込み認証サービスの提供に加え、Laravelは特定のリソースに対するユーザーアクションを認可する手軽な方法も提供しています。たとえば、あるユーザーが認証されていても、アプリケーションが管理している特定のEloquentモデルまたはデータベースレコードを更新や削除する権限を持っていない場合があるでしょう。Laravelの認可機能は、こうしたタイプの認可チェックを管理するための簡単で組織化された方法を提供します。In addition to providing built-in authentication[/docs/{{version}}/authentication] services, Laravel also provides a simple way to authorize user actions against a given resource. For example, even though a user is authenticated, they may not be authorized to update or delete certain Eloquent models or database records managed by your application. Laravel's authorization features provide an easy, organized way of managing these types of authorization checks.
Laravelは、アクションを認可する2つの主要な方法を提供します。ゲートとポリシーです。ゲートとポリシーは、ルートやコントローラのようなものだと考えてください。ゲートは認可のためのクロージャベースのシンプルなアプローチを提供します。一方でポリシーはコントローラのように、特定のモデルやリソース周辺のロジックをひとかたまりにまとめます。このドキュメントでは、最初にゲートを説明し、その後でポリシーを見ていきましょう。Laravel provides two primary ways of authorizing actions: gates[#gates] and policies[#creating-policies]. Think of gates and policies like routes and controllers. Gates provide a simple, closure-based approach to authorization while policies, like controllers, group logic around a particular model or resource. In this documentation, we'll explore gates first and then examine policies.
アプリケーションを構築するときに、ゲートのみを使用するか、ポリシーのみを使用するかを選択する必要はありません。ほとんどのアプリケーションには、ゲートとポリシーが混在する可能性が高く、それはまったく問題ありません。ゲートは、管理者ダッシュボードの表示など、モデルやリソースに関連しないアクションに最も適しています。対照的に、特定のモデルまたはリソースのアクションを認可する場合は、ポリシーを使用する必要があります。You do not need to choose between exclusively using gates or exclusively using policies when building an application. Most applications will most likely contain some mixture of gates and policies, and that is perfectly fine! Gates are most applicable to actions that are not related to any model or resource, such as viewing an administrator dashboard. In contrast, policies should be used when you wish to authorize an action for a particular model or resource.
ゲートGates
ゲートの作成Writing Gates
ポリシーを使用して認可ルールを整理することを検討する必要があります。WarningGates are a great way to learn the basics of Laravel's authorization features; however, when building robust Laravel applications you should consider using policies[#creating-policies] to organize your authorization rules.
Warning! ゲートは、Laravelの認可機能の基本を学ぶための優れた方法です。ただし、堅牢なLaravelアプリケーションを構築するときは、
ゲートは、ユーザーが特定のアクションを実行することを許可されているかどうかを判断する単なるクロージャです。通常、ゲートは、Gate
ファサードを使用してApp\Providers\AuthServiceProvider
クラスのboot
メソッド内で定義されます。ゲートは常に最初の引数としてユーザーインスタンスを受け取り、オプションで関連するEloquentモデルなどの追加の引数を受け取る場合があります。Gates are simply closures that determine if a user is authorized to perform a given action. Typically, gates are defined within the boot
method of the App\Providers\AuthServiceProvider
class using the Gate
facade. Gates always receive a user instance as their first argument and may optionally receive additional arguments such as a relevant Eloquent model.
以下の例では、ユーザーが特定のApp\Models\Post
モデルを更新できるかどうかを判断するためのゲートを定義します。ユーザーのid
と、投稿を作成したユーザーのuser_id
を比較することで、このゲートは可否を判定します。In this example, we'll define a gate to determine if a user can update a given App\Models\Post
model. The gate will accomplish this by comparing the user's id
against the user_id
of the user that created the post:
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
/**
* 全認証/認可サービスの登録
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
}
コントローラと同様に、ゲートもクラスコールバック配列を使用して定義できます。Like controllers, gates may also be defined using a class callback array:
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
/**
* 全認証/認可サービスの登録
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', [PostPolicy::class, 'update']);
}
アクションの認可Authorizing Actions
ゲートを使用してアクションを認可するには、Gate
ファサードが提供するallows
かdenies
メソッドを使用する必要があります。現在認証済みのユーザーをこれらのメソッドに渡す必要はないことに注意してください。Laravelは自動的にユーザーをゲートクロージャに引き渡します。認可が必要なアクションを実行する前に、アプリケーションのコントローラ内でゲート認可メソッドを呼び出すのが一般的です。To authorize an action using gates, you should use the allows
or denies
methods provided by the Gate
facade. Note that you are not required to pass the currently authenticated user to these methods. Laravel will automatically take care of passing the user into the gate closure. It is typical to call the gate authorization methods within your application's controllers before performing an action that requires authorization:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class PostController extends Controller
{
/**
* 指定した投稿を更新
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post)
{
if (! Gate::allows('update-post', $post)) {
abort(403);
}
// 投稿を更新…
}
}
現在認証済みユーザー以外のユーザーがアクションの実行を許可されているかを確認する場合は、Gate
ファサードでforUser
メソッドを使用します。If you would like to determine if a user other than the currently authenticated user is authorized to perform an action, you may use the forUser
method on the Gate
facade:
if (Gate::forUser($user)->allows('update-post', $post)) {
// ユーザーは投稿を更新可能
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// ユーザーは投稿を更新不可能
}
any
またはnone
メソッドを使用して、一度に複数のアクション認可を確認できます。You may authorize multiple actions at a time using the any
or none
methods:
if (Gate::any(['update-post', 'delete-post'], $post)) {
// ユーザーは投稿を更新または削除可能
}
if (Gate::none(['update-post', 'delete-post'], $post)) {
// ユーザーは投稿を更新または削除不可能
}
認可または例外を投げるAuthorizing Or Throwing Exceptions
アクションを認可をチェックし、ユーザーが指定のアクションの実行を許可されていない場合は、Illuminate\Auth\Access\AuthorizationException
を自動で投げたい場合は、Gate
ファサードのauthorize
メソッドを使用します。AuthorizationException
のインスタンスは、Laravelの例外ハンドラによって自動的に403HTTPレスポンスへ変換されます。If you would like to attempt to authorize an action and automatically throw an Illuminate\Auth\Access\AuthorizationException
if the user is not allowed to perform the given action, you may use the Gate
facade's authorize
method. Instances of AuthorizationException
are automatically converted to a 403 HTTP response by Laravel's exception handler:
Gate::authorize('update-post', $post);
// アクションは認可されている
追加コンテキストの提供Supplying Additional Context
アビリティを認可するためのゲートメソッド(allows
、denis
、check
、any
、none
、authorize
、can
、cannot
)と認可Bladeディレクティブ(@can
、@cannot
、@canany
)は、2番目の引数として配列を取れます。これらの配列要素は、パラメータとしてゲートクロージャに渡され、認可を決定する際の追加のコンテキストに使用できます。The gate methods for authorizing abilities (allows
, denies
, check
, any
, none
, authorize
, can
, cannot
) and the authorization Blade directives[#via-blade-templates] (@can
, @cannot
, @canany
) can receive an array as their second argument. These array elements are passed as parameters to the gate closure, and can be used for additional context when making authorization decisions:
use App\Models\Category;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::define('create-post', function (User $user, Category $category, $pinned) {
if (! $user->canPublishToGroup($category->group)) {
return false;
} elseif ($pinned && ! $user->canPinPosts()) {
return false;
}
return true;
});
if (Gate::check('create-post', [$category, $pinned])) {
// ユーザーは投稿を作成可能
}
ゲートのレスポンスGate Responses
これまで、単純な論理値を返すゲートのみ見てきました。しかし、エラーメッセージなどのより詳細なレスポンスを返したい場合もあります。これには、ゲートからIlluminate\Auth\Access\Response
を返してください。So far, we have only examined gates that return simple boolean values. However, sometimes you may wish to return a more detailed response, including an error message. To do so, you may return an Illuminate\Auth\Access\Response
from your gate:
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
メソッドを使用して、ゲートから返される完全な認可レスポンスを取得できます。Even when you return an authorization response from your gate, the Gate::allows
method will still return a simple boolean value; however, you may use the Gate::inspect
method to get the full authorization response returned by the gate:
$response = Gate::inspect('edit-settings');
if ($response->allowed()) {
// アクションは認可されている
} else {
echo $response->message();
}
アクションが認可されていない場合にAuthorizationException
を投げるGate::authorize
メソッドを使用すると、認可レスポンスが提供するエラーメッセージがHTTPレスポンスへ伝播されます。When using the Gate::authorize
method, which throws an AuthorizationException
if the action is not authorized, the error message provided by the authorization response will be propagated to the HTTP response:
Gate::authorize('edit-settings');
// アクションは認可されている
HTTPレスポンスステータスのカスタマイズCustomizing The HTTP Response Status
ゲートがアクションを拒否すると、403
HTTPレスポンスを返します。しかし場合により、別のHTTPステータスコードを返すほうが、便利なことがあります。認可チェックに失敗したときに返すHTTPステータスコードは、Illuminate\Auth\Access\Response
クラスのdenyWithStatus
静的コンストラクタを使用してカスタマイズできます。When an action is denied via a Gate, a 403
HTTP response is returned; however, it can sometimes be useful to return an alternative HTTP status code. You may customize the HTTP status code returned for a failed authorization check using the denyWithStatus
static constructor on the Illuminate\Auth\Access\Response
class:
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
メソッドを提供しています。Because hiding resources via a 404
response is such a common pattern for web applications, the denyAsNotFound
method is offered for convenience:
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();
});
ゲートチェックの割り込みIntercepting Gate Checks
特定のユーザーにすべての機能を付与したい場合があります。before
メソッドを使用して、他のすべての認可チェックの前に実行するクロージャを定義できます。Sometimes, you may wish to grant all abilities to a specific user. You may use the before
method to define a closure that is run before all other authorization checks:
use Illuminate\Support\Facades\Gate;
Gate::before(function ($user, $ability) {
if ($user->isAdministrator()) {
return true;
}
});
before
クロージャがnull以外の結果を返した場合、その結果を許可チェックの結果とみなします。If the before
closure returns a non-null result that result will be considered the result of the authorization check.
after
メソッドを使用して、他のすべての認可チェックの後に実行されるクロージャを定義できます。You may use the after
method to define a closure to be executed after all other authorization checks:
Gate::after(function ($user, $ability, $result, $arguments) {
if ($user->isAdministrator()) {
return true;
}
});
before
メソッドと同様に、after
クロージャがnull以外の結果を返した場合、その結果は認可チェックの結果とみなします。Similar to the before
method, if the after
closure returns a non-null result that result will be considered the result of the authorization check.
インライン認可Inline Authorization
時には、現在認証されているユーザーが、あるアクションを実行する認可を持っているかを、そのアクションに対応する専用のゲートを書かずに判断したいこともあるでしょう。Laravelでは、Gate::allowIf
やGate::denyIf
メソッドを使い、「インライン」での認可チェックを行うことができます。Occasionally, you may wish to determine if the currently authenticated user is authorized to perform a given action without writing a dedicated gate that corresponds to the action. Laravel allows you to perform these types of "inline" authorization checks via the Gate::allowIf
and Gate::denyIf
methods:
use Illuminate\Support\Facades\Gate;
Gate::allowIf(fn ($user) => $user->isAdministrator());
Gate::denyIf(fn ($user) => $user->banned());
アクションが認可されていない場合や、現在認証されているユーザーがいない場合、Laravelは自動的にIlluminate\Auth\Access\AuthorizationException
という例外を投げます。AuthorizationException
のインスタンスは、Laravelの例外ハンドラが、自動的に403 HTTPレスポンスへ変換します。If the action is not authorized or if no user is currently authenticated, Laravel will automatically throw an Illuminate\Auth\Access\AuthorizationException
exception. Instances of AuthorizationException
are automatically converted to a 403 HTTP response by Laravel's exception handler.
ポリシーの作成Creating Policies
ポリシーの生成Generating Policies
ポリシーは、特定のモデルまたはリソースに関する認可ロジックを集めたクラスです。たとえば、アプリケーションがブログの場合、App\Models\Post
モデルと投稿の作成や更新などのユーザーアクションを認可するためのPostモデルと対応するApp\Policies\PostPolicy
があるでしょう。Policies are classes that organize authorization logic around a particular model or resource. For example, if your application is a blog, you may have a App\Models\Post
model and a corresponding App\Policies\PostPolicy
to authorize user actions such as creating or updating posts.
make:policy
Artisanコマンドを使用してポリシーを生成できます。生成するポリシーはapp/Policies
ディレクトリへ配置します。このディレクトリがアプリケーションに存在しない場合、Laravelが作成します。You may generate a policy using the make:policy
Artisan command. The generated policy will be placed in the app/Policies
directory. If this directory does not exist in your application, Laravel will create it for you:
php artisan make:policy PostPolicy
make:policy
コマンドは、空のポリシークラスを生成します。リソースの表示、作成、更新、削除に関連するポリシーメソッドのサンプルを含んだクラスを生成する場合は、コマンドの実行時に--model
オプションを指定します。The make:policy
command will generate an empty policy class. If you would like to generate a class with example policy methods related to viewing, creating, updating, and deleting the resource, you may provide a --model
option when executing the command:
php artisan make:policy PostPolicy --model=Post
ポリシーの登録Registering Policies
ポリシークラスを作成したら、登録する必要があります。ポリシーの登録とは、特定のモデルタイプに対するアクションを認可するときに、使用するポリシーをLaravelに指示する方法です。Once the policy class has been created, it needs to be registered. Registering policies is how we can inform Laravel which policy to use when authorizing actions against a given model type.
新しいLaravelアプリケーションに含まれているApp\Providers\AuthServiceProvider
には、Eloquentモデルを対応するポリシーにマップするpolicies
プロパティが含まれています。ポリシーを登録すると、特定のEloquentモデルに対するアクションを認可するときに使用するポリシーがLaravelに指示されます。The App\Providers\AuthServiceProvider
included with fresh Laravel applications contains a policies
property which maps your Eloquent models to their corresponding policies. Registering a policy will instruct Laravel which policy to utilize when authorizing actions against a given Eloquent model:
<?php
namespace App\Providers;
use App\Models\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* アプリケーションのポリシーマッピング
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* 全アプリケーション認証/認可サービス登録
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
ポリシーの自動検出Policy Auto-Discovery
モデルポリシーを手作業で登録する代わりに、モデルとポリシーが標準のLaravel命名規約に従っている限り、Laravelはポリシーを自動的に検出できます。具体的にポリシーは、モデルを含むディレクトリが存在する階層より上のPolicies
ディレクトリにある必要があります。したがって、たとえばモデルはapp/Models
ディレクトリに配置し、ポリシーはapp/Policies
ディレクトリに配置する場合があるでしょう。この場合、Laravelはapp/Models/Policies
、次にapp/Policies
のポリシーをチェックします。さらに、ポリシー名はモデル名と一致し、Policy
サフィックスが付いている必要があります。したがって、User
モデルはUserPolicy
ポリシークラスに対応します。Instead of manually registering model policies, Laravel can automatically discover policies as long as the model and policy follow standard Laravel naming conventions. Specifically, the policies must be in a Policies
directory at or above the directory that contains your models. So, for example, the models may be placed in the app/Models
directory while the policies may be placed in the app/Policies
directory. In this situation, Laravel will check for policies in app/Models/Policies
then app/Policies
. In addition, the policy name must match the model name and have a Policy
suffix. So, a User
model would correspond to a UserPolicy
policy class.
独自のポリシー検出ロジックを定義する場合は、Gate::guessPolicyNamesUsing
メソッドを使用してカスタムポリシー検出コールバックを登録できます。通常、このメソッドは、アプリケーションのAuthServiceProvider
のboot
メソッドから呼び出す必要があります。If you would like to define your own policy discovery logic, you may register a custom policy discovery callback using the Gate::guessPolicyNamesUsing
method. Typically, this method should be called from the boot
method of your application's AuthServiceProvider
:
use Illuminate\Support\Facades\Gate;
Gate::guessPolicyNamesUsing(function ($modelClass) {
// 指定されたモデルに対するポリシークラスの名前を返す…
});
Warning!
AuthServiceProvider
で明示的にマッピングされるポリシーは、自動検出される可能性のあるポリシーよりも優先されます。WarningAny policies that are explicitly mapped in yourAuthServiceProvider
will take precedence over any potentially auto-discovered policies.
ポリシーの作成Writing Policies
ポリシーメソッドPolicy Methods
ポリシークラスを登録したら、認可するアクションごとにメソッドを追加できます。例として、あるApp\Models\User
があるApp\Models\Post
インスタンスを更新できるかどうかを決定するPostPolicy
でupdate
メソッドを定義してみましょう。Once the policy class has been registered, you may add methods for each action it authorizes. For example, let's define an update
method on our PostPolicy
which determines if a given App\Models\User
can update a given App\Models\Post
instance.
update
メソッドは引数としてUser
とPost
インスタンスを受け取り、そのユーザーが指定したPost
を更新する権限があるかどうかを示すtrue
またはfalse
を返す必要があります。したがって、この例では、ユーザーのid
が投稿のuser_id
と一致することを確認しています。The update
method will receive a User
and a Post
instance as its arguments, and should return true
or false
indicating whether the user is authorized to update the given Post
. So, in this example, we will verify that the user's id
matches the user_id
on the post:
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* 指定した投稿をユーザーが更新可能かを判定
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
ポリシーが認可するさまざまなアクションの必要に合わせ、ポリシーに追加のメソッドをどんどん定義できます。たとえば、view
またはdelete
メソッドを定義して、さまざまなPost
関連のアクションを認可できますが、ポリシーメソッドには任意の名前を付けることができることを覚えておいてください。You may continue to define additional methods on the policy as needed for the various actions it authorizes. For example, you might define view
or delete
methods to authorize various Post
related actions, but remember you are free to give your policy methods any name you like.
Artisanコンソールを介してポリシーを生成するときに--model
オプションを使用した場合、はじめからviewAny
、view
、create
、update
、delete
、restore
、forceDelete
アクションのメソッドが用意されます。If you used the --model
option when generating your policy via the Artisan console, it will already contain methods for the viewAny
, view
, create
, update
, delete
, restore
, and forceDelete
actions.
サービスコンテナを介して解決されるため、ポリシーのコンストラクターで必要な依存関係をタイプヒントして、自動的に依存注入することができます。NoteAll policies are resolved via the Laravel service container[/docs/{{version}}/container], allowing you to type-hint any needed dependencies in the policy's constructor to have them automatically injected.
Note:すべてのポリシーはLaravel
ポリシーのレスポンスPolicy Responses
これまで、単純な論理値値を返すポリシーメソッドについてのみ説明してきました。しかし、エラーメッセージなどより詳細なレスポンスを返したい場合があります。これにはポリシーメソッドからIlluminate\Auth\Access\Response
インスタンスを返してください。So far, we have only examined policy methods that return simple boolean values. However, sometimes you may wish to return a more detailed response, including an error message. To do so, you may return an Illuminate\Auth\Access\Response
instance from your policy method:
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
/**
* 指定された投稿をユーザーが更新可能か判定
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return \Illuminate\Auth\Access\Response
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('You do not own this post.');
}
ポリシーから認可レスポンスを返す場合でも、Gate::allows
メソッドは単純な論理値を返します。ただし、Gate::inspect
メソッドを使用して、ゲートが返す完全な認可レスポンスを取得できます。When returning an authorization response from your policy, the Gate::allows
method will still return a simple boolean value; however, you may use the Gate::inspect
method to get the full authorization response returned by the gate:
use Illuminate\Support\Facades\Gate;
$response = Gate::inspect('update', $post);
if ($response->allowed()) {
// アクションは認可されている
} else {
echo $response->message();
}
アクションが認可されていない場合にAuthorizationException
を投げるGate::authorize
メソッドを使用すると、認可レスポンスが提供するエラーメッセージがHTTPレスポンスへ伝播されます。When using the Gate::authorize
method, which throws an AuthorizationException
if the action is not authorized, the error message provided by the authorization response will be propagated to the HTTP response:
Gate::authorize('update', $post);
// アクションは認可されている
HTTPレスポンスステータスのカスタマイズCustomizing The HTTP Response Status
ポリシーメソッドがアクションを拒否すると、403
HTTPレスポンスを返します。しかし場合により、別のHTTPステータスコードを返すほうが、便利なことがあります。認可チェックに失敗したときに返すHTTPステータスコードは、Illuminate\Auth\Access\Response
クラスのdenyWithStatus
静的コンストラクタを使用してカスタマイズできます。When an action is denied via a policy method, a 403
HTTP response is returned; however, it can sometimes be useful to return an alternative HTTP status code. You may customize the HTTP status code returned for a failed authorization check using the denyWithStatus
static constructor on the Illuminate\Auth\Access\Response
class:
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
/**
* 指定ポストがユーザーにより更新可能であるか決定
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return \Illuminate\Auth\Access\Response
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyWithStatus(404);
}
404
レスポンスによるリソースの隠蔽はウェブアプリケーションでは常套手段なため、使いやすいようにdenyAsNotFound
メソッドを提供しています。Because hiding resources via a 404
response is such a common pattern for web applications, the denyAsNotFound
method is offered for convenience:
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
/**
* 指定ポストがユーザーにより更新可能であるか決定
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return \Illuminate\Auth\Access\Response
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyAsNotFound();
}
モデルのないメソッドMethods Without Models
一部のポリシーメソッドは、現在認証済みユーザーのインスタンスのみを受け取ります。この状況は、create
アクションを認可するばあいに頻繁に見かけます。たとえば、ブログを作成している場合、ユーザーが投稿の作成を認可されているかを確認したい場合があります。このような状況では、ポリシーメソッドはユーザーインスタンスのみを受け取る必要があります。Some policy methods only receive an instance of the currently authenticated user. This situation is most common when authorizing create
actions. For example, if you are creating a blog, you may wish to determine if a user is authorized to create any posts at all. In these situations, your policy method should only expect to receive a user instance:
/**
* 指定ユーザーが投稿を作成可能か確認
*
* @param \App\Models\User $user
* @return bool
*/
public function create(User $user)
{
return $user->role == 'writer';
}
ゲストユーザーGuest Users
デフォルトでは、受信HTTPリクエストが認証済みユーザーによって開始されたものでない場合、すべてのゲートとポリシーは自動的にfalse
を返します。ただし、「オプションの」タイプヒントを宣言するか、ユーザーの引数定義でnull
のデフォルト値を指定することで、これらの認可チェックをゲートとポリシーに渡すことができます。By default, all gates and policies automatically return false
if the incoming HTTP request was not initiated by an authenticated user. However, you may allow these authorization checks to pass through to your gates and policies by declaring an "optional" type-hint or supplying a null
default value for the user argument definition:
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* 指定した投稿をユーザーが更新可能かを判定
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return bool
*/
public function update(?User $user, Post $post)
{
return optional($user)->id === $post->user_id;
}
}
ポリシーフィルタPolicy Filters
ある特定のユーザーには、特定のポリシー内のすべてのアクションを認可したい場合があります。これには、ポリシーで「before」メソッドを定義します。before
メソッドは、ポリシー上の他のメソッドの前に実行されるため、目的のポリシーメソッドが実際に呼び出される前にアクションを認可する機会に利用できます。この機能は、アプリケーション管理者にアクションの実行を許可するために最も一般的に使用されます。For certain users, you may wish to authorize all actions within a given policy. To accomplish this, define a before
method on the policy. The before
method will be executed before any other methods on the policy, giving you an opportunity to authorize the action before the intended policy method is actually called. This feature is most commonly used for authorizing application administrators to perform any action:
use App\Models\User;
/**
* 事前認可チェックの実行
*
* @param \App\Models\User $user
* @param string $ability
* @return void|bool
*/
public function before(User $user, $ability)
{
if ($user->isAdministrator()) {
return true;
}
}
特定のタイプのユーザー全員の認可チェックを拒否したい場合は、before
メソッドからfalse
を返してください。null
を返す場合は、認可チェックはポリシーメソッドへ委ねられます。If you would like to deny all authorization checks for a particular type of user then you may return false
from the before
method. If null
is returned, the authorization check will fall through to the policy method.
Warning! ポリシークラスの
before
メソッドは、チェックしている機能の名前と一致する名前のメソッドがクラスに含まれていない場合は呼び出されません。WarningThebefore
method of a policy class will not be called if the class doesn't contain a method with a name matching the name of the ability being checked.
ポリシーを使用したアクションの認可Authorizing Actions Using Policies
ユーザーモデル経由Via The User Model
Laravelアプリケーションに含まれているApp\Models\User
モデルには、アクションを認可するための2つの便利なメソッドcan
とcannot
が含まれています。can
メソッドとcannot
メソッドは、認可するアクションの名前と関連するモデルを受け取ります。たとえば、ユーザーが特定のApp\Models\Post
モデルを更新する権限を持っているかどうかを確認しましょう。通常、これはコントローラメソッド内で実行されます。The App\Models\User
model that is included with your Laravel application includes two helpful methods for authorizing actions: can
and cannot
. The can
and cannot
methods receive the name of the action you wish to authorize and the relevant model. For example, let's determine if a user is authorized to update a given App\Models\Post
model. Typically, this will be done within a controller method:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* 指定した投稿を更新
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post)
{
if ($request->user()->cannot('update', $post)) {
abort(403);
}
// 投稿を更新…
}
}
指定したモデルのポリシーが登録されているの場合、can
メソッドは自動的に適切なポリシーを呼び出し、論理値の結果を返します。モデルにポリシーが登録されていない場合、can
メソッドは、指定されたアクション名に一致するクロージャベースのゲートを呼び出そうとします。If a policy is registered[#registering-policies] for the given model, the can
method will automatically call the appropriate policy and return the boolean result. If no policy is registered for the model, the can
method will attempt to call the closure-based Gate matching the given action name.
モデルを必要としないアクションActions That Don't Require Models
一部のアクションは、モデルインスタンスを必要としないcreate
などのポリシーメソッドに対応する場合があることに注意してください。このような状況では、クラス名をcan
メソッドに渡すことができます。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。Remember, some actions may correspond to policy methods like create
that do not require a model instance. In these situations, you may pass a class name to the can
method. The class name will be used to determine which policy to use when authorizing the action:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* 投稿を作成
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if ($request->user()->cannot('create', Post::class)) {
abort(403);
}
// 投稿を作成…
}
}
コントローラヘルパ経由Via Controller Helpers
Laravelは、App\Models\User
モデルが提供する便利なメソッドに加えて、App\Http\Controllers\Controller
基本クラスを拡張する任意のコントローラに役立つauthorize
メソッドを提供します。In addition to helpful methods provided to the App\Models\User
model, Laravel provides a helpful authorize
method to any of your controllers which extend the App\Http\Controllers\Controller
base class.
can
メソッドと同様に、このメソッドは、認可するアクションの名前とリレーションモデルを受け入れます。アクションが認可されていない場合、authorize
メソッドはIlluminate\Auth\Access\AuthorizationException
例外を投げ、Laravel例外ハンドラは自動的に403ステータスコードのHTTPレスポンスに変換します。Like the can
method, this method accepts the name of the action you wish to authorize and the relevant model. If the action is not authorized, the authorize
method will throw an Illuminate\Auth\Access\AuthorizationException
exception which the Laravel exception handler will automatically convert to an HTTP response with a 403 status code:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* 指定したブログ投稿の更新
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// 現在のユーザーはこのブログ投稿を更新可能
}
}
モデルを必要としないアクションActions That Don't Require Models
すでに説明したように、create
などの一部のポリシーメソッドはモデルインスタンスを必要としません。このような状況では、クラス名をauthorize
メソッドに渡す必要があります。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。As previously discussed, some policy methods like create
do not require a model instance. In these situations, you should pass a class name to the authorize
method. The class name will be used to determine which policy to use when authorizing the action:
use App\Models\Post;
use Illuminate\Http\Request;
/**
* 新しいブログ投稿の作成
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request)
{
$this->authorize('create', Post::class);
// 現在のユーザーはブログ投稿を作成可能
}
リソースコントローラの認可Authorizing Resource Controllers
リソースコントローラを使用している場合は、コントローラのコンストラクターでauthorizeResource
メソッドを使用できます。このメソッドは、適切なcan
ミドルウェア定義をリソースコントローラのメソッドにアタッチします。If you are utilizing resource controllers[/docs/{{version}}/controllers#resource-controllers], you may make use of the authorizeResource
method in your controller's constructor. This method will attach the appropriate can
middleware definitions to the resource controller's methods.
authorizeResource
メソッドは、最初の引数としてモデルのクラス名を受け入れ、2番目の引数としてモデルのIDを含むルート/リクエストパラメーターの名前を受け入れます。リソースコントローラが--model
フラグを使用して作成されていることを確認して、必要なメソッド引数とタイプヒントが含まれるようにしてください。The authorizeResource
method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument. You should ensure your resource controller[/docs/{{version}}/controllers#resource-controllers] is created using the --model
flag so that it has the required method signatures and type hints:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* コントローラインスタンスの生成
*
* @return void
*/
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}
以下のコントローラメソッドは、対応するポリシーメソッドにマップされています。リクエストが特定のコントローラメソッドにルーティングされると、コントローラメソッドが実行される前に、対応するポリシーメソッドが自動的に呼び出されます。The following controller methods will be mapped to their corresponding policy method. When requests are routed to the given controller method, the corresponding policy method will automatically be invoked before the controller method is executed:
コントローラメソッドController Method | ポリシーメソッドPolicy Method |
---|---|
indexindex | viewAnyviewAny |
showshow | viewview |
createcreate | createcreate |
storestore | createcreate |
editedit | updateupdate |
updateupdate | updateupdate |
destroydestroy | deletedelete |
Note:
make:policy
コマンドを--model
オプションとともに使用し、特定のモデルのポリシークラスを手早く生成できます。php artisan make:policy PostPolicy --model=Post
NoteYou may use themake:policy
command with the--model
option to quickly generate a policy class for a given model:php artisan make:policy PostPolicy --model=Post
.
ミドルウェア経由Via Middleware
Laravelには、受信リクエストがルートやコントローラに到達する前にアクションを認可できるミドルウェアが含まれています。デフォルトでは、Illuminate\Auth\Middleware\Authorize
ミドルウェアにはApp\Http\Kernel
クラスのcan
キーが割り当てられています。can
ミドルウェアを使用して、ユーザーが投稿を更新できることを認可する例を見てみましょう。Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers. By default, the Illuminate\Auth\Middleware\Authorize
middleware is assigned the can
key in your App\Http\Kernel
class. Let's explore an example of using the can
middleware to authorize that a user can update a post:
use App\Models\Post;
Route::put('/post/{post}', function (Post $post) {
// 現在のユーザーは投稿を更新可能
})->middleware('can:update,post');
この例では、can
ミドルウェアに2つの引数を渡します。1つ目は認可するアクションの名前であり、2つ目はポリシーメソッドに渡すルートパラメーターです。この場合、暗黙のモデルバインディングを使用しているため、App\Models\Post
モデルがポリシーメソッドに渡されます。ユーザーが特定のアクションを実行する権限を持っていない場合、ミドルウェアは403ステータスコードのHTTPレスポンスを返します。In this example, we're passing the can
middleware two arguments. The first is the name of the action we wish to authorize and the second is the route parameter we wish to pass to the policy method. In this case, since we are using implicit model binding[/docs/{{version}}/routing#implicit-binding], a App\Models\Post
model will be passed to the policy method. If the user is not authorized to perform the given action, an HTTP response with a 403 status code will be returned by the middleware.
これは簡単に、can
メソッドを使い、can
ミドルウェアをルートへ指定できます。For convenience, you may also attach the can
middleware to your route using the can
method:
use App\Models\Post;
Route::put('/post/{post}', function (Post $post) {
// 現在のユーザーは投稿を更新可能
})->can('update', 'post');
モデルを必要としないアクションActions That Don't Require Models
繰り返しますが、create
のようないくつかのポリシーメソッドはモデルインスタンスを必要としません。このような状況では、クラス名をミドルウェアに渡すことができます。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。Again, some policy methods like create
do not require a model instance. In these situations, you may pass a class name to the middleware. The class name will be used to determine which policy to use when authorizing the action:
Route::post('/post', function () {
// 現在のユーザーは投稿を作成可能
})->middleware('can:create,App\Models\Post');
ミドルウェア定義の中で、クラス名全体を文字列で指定するのは面倒です。そのため、can
メソッドを使って、can
ミドルウェアをルートへ指定できます。Specifying the entire class name within a string middleware definition can become cumbersome. For that reason, you may choose to attach the can
middleware to your route using the can
method:
use App\Models\Post;
Route::post('/post', function () {
// 現在のユーザーは投稿を作成可能
})->can('create', Post::class);
Bladeテンプレート経由Via Blade Templates
Bladeテンプレートを作成するとき、ユーザーが特定のアクションを実行する許可がある場合にのみ、ページの一部を表示したい場合があります。たとえば、ユーザーが実際に投稿を更新できる場合にのみ、ブログ投稿の更新フォームを表示したい場合があります。この状況では、@can
および@cannot
ディレクティブを使用できます。When writing Blade templates, you may wish to display a portion of the page only if the user is authorized to perform a given action. For example, you may wish to show an update form for a blog post only if the user can actually update the post. In this situation, you may use the @can
and @cannot
directives:
@can('update', $post)
<!-- 現在のユーザーは投稿を更新可能 -->
@elsecan('create', App\Models\Post::class)
<!-- 現在のユーザーは新しい投稿を作成不可能 -->
@else
<!-- ... -->
@endcan
@cannot('update', $post)
<!-- 現在のユーザーは投稿を更新不可能 -->
@elsecannot('create', App\Models\Post::class)
<!-- 現在のユーザーは新しい投稿を作成可能 -->
@endcannot
これらのディレクティブは、@if
と@unless
ステートメントを短く記述するための便利な短縮形です。上記の@can
および@cannot
ステートメントは、以下のステートメントと同等です。These directives are convenient shortcuts for writing @if
and @unless
statements. The @can
and @cannot
statements above are equivalent to the following statements:
@if (Auth::user()->can('update', $post))
<!-- 現在のユーザーは投稿を更新可能 -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- 現在のユーザーは投稿を更新不可能 -->
@endunless
また、ユーザーが複数のアクションの実行を認可されているかを判定することもできます。これには、@canany
ディレクティブを使用します。You may also determine if a user is authorized to perform any action from a given array of actions. To accomplish this, use the @canany
directive:
@canany(['update', 'view', 'delete'], $post)
<!-- 現在のユーザーは、投稿を更新、表示、削除可能 -->
@elsecanany(['create'], \App\Models\Post::class)
<!-- 現在のユーザーは投稿を作成可能 -->
@endcanany
モデルを必要としないアクションActions That Don't Require Models
他のほとんどの認可メソッドと同様に、アクションがモデルインスタンスを必要としない場合は、クラス名を@can
および@cannot
ディレクティブに渡すことができます。Like most of the other authorization methods, you may pass a class name to the @can
and @cannot
directives if the action does not require a model instance:
@can('create', App\Models\Post::class)
<!-- 現在のユーザーは投稿を作成可能 -->
@endcan
@cannot('create', App\Models\Post::class)
<!-- 現在のユーザーは投稿を作成不可能 -->
@endcannot
追加コンテキストの提供Supplying Additional Context
ポリシーを使用してアクションを認可する場合、2番目の引数としてさまざまな認可関数とヘルパに配列を渡すことができます。配列の最初の要素は、呼び出すポリシーを決定するために使用され、残りの配列要素は、パラメーターとしてポリシーメソッドに渡され、認可の決定を行う際の追加のコンテキストに使用できます。たとえば、追加の$category
パラメータを含む次のPostPolicy
メソッド定義について考えてみます。When authorizing actions using policies, you may pass an array as the second argument to the various authorization functions and helpers. The first element in the array will be used to determine which policy should be invoked, while the rest of the array elements are passed as parameters to the policy method and can be used for additional context when making authorization decisions. For example, consider the following PostPolicy
method definition which contains an additional $category
parameter:
/**
* 指定された投稿をユーザーが更新可能か判定
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @param int $category
* @return bool
*/
public function update(User $user, Post $post, int $category)
{
return $user->id === $post->user_id &&
$user->canUpdateCategory($category);
}
認証済みユーザーが特定の投稿を更新できるか判断する場合、次のようにこのポリシーメソッドを呼び出すことができます。When attempting to determine if the authenticated user can update a given post, we can invoke this policy method like so:
/**
* 指定ブログ投稿を更新
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', [$post, $request->category]);
// 現在のユーザーはブログ投稿を更新可能
}