イントロダクションIntroduction
Laravelは組み込み済みの認証サービスに加え、特定のリソースに対するユーザーアクションを認可する簡単な手法も提供しています。認証と同様に、Laravelの認可のアプローチはシンプルで、主に2つの認可アクションの方法があります。ゲートとポリシーです。In addition to providing authentication[/docs/{{version}}/authentication] services out of the box, Laravel also provides a simple way to authorize user actions against a given resource. Like authentication, Laravel's approach to authorization is simple, and there are two primary ways of authorizing actions: gates and policies.
ゲートとポリシーは、ルートとコントローラのようなものであると考えてください。ゲートはシンプルな、クロージャベースのアプローチを認可に対してとっています。一方のコントローラに似ているポリシーとは、特定のモデルやリソースに対するロジックをまとめたものです。最初にゲートを説明し、次にポリシーを確認しましょう。Think of gates and policies like routes and controllers. Gates provide a simple, Closure based approach to authorization while policies, like controllers, group their logic around a particular model or resource. 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 a mixture of gates and policies, and that is perfectly fine! Gates are most applicable to actions which 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
ゲートは、特定のアクションを実行できる許可が、あるユーザーにあるかを決めるクロージャのことです。通常は、App\Providers\AuthServiceProvider
の中で、Gate
ファサードを使用し、定義します。ゲートは常に最初の引数にユーザーインスタンスを受け取ります。関連するEloquentモデルのような、追加の引数をオプションとして受け取ることもできます。Gates are Closures that determine if a user is authorized to perform a given action and are typically defined in 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:
/**
* 全認証/認可サービスの登録
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
コントローラのように、ゲートはClass@method
形式のコールバック文字列を使い定義することも可能です。Gates may also be defined using a Class@method
style callback string, like controllers:
/**
* 全認証/認可サービスの登録
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', 'App\Policies\PostPolicy@update');
}
リソースゲートResource Gates
resource
メソッドを使用すれば、一度に複数のゲートを定義できます。You may also define multiple Gate abilities at once using the resource
method:
Gate::resource('posts', 'App\Policies\PostPolicy');
これは次のゲート定義とまったく同じです。This is identical to manually defining the following Gate definitions:
Gate::define('posts.view', 'App\Policies\PostPolicy@view');
Gate::define('posts.create', 'App\Policies\PostPolicy@create');
Gate::define('posts.update', 'App\Policies\PostPolicy@update');
Gate::define('posts.delete', 'App\Policies\PostPolicy@delete');
view
、create
、update
、delete
アビリティが、デフォルトで定義されます。resource
メソッドに第3引数として配列を渡し、デフォルトのアビリティのオーバーライドが可能です。配列のキーでアビリティの名前、値でメソッド名を定義します。例として、新しくposts.image
とposts.photo
のゲート定義を2つだけ作成してみましょう。By default, the view
, create
, update
, and delete
abilities will be defined. You may override the default abilities by passing an array as a third argument to the resource
method. The keys of the array define the names of the abilities while the values define the method names. For example, the following code will only create two new Gate definitions - posts.image
and posts.photo
:
Gate::resource('posts', 'PostPolicy', [
'image' => 'updateImage',
'photo' => 'updatePhoto',
]);
アクションの認可Authorizing Actions
ゲートを使用しアクションを認可するには、allows
とdenies
メソッドを使ってください。両メソッドに現在認証中のユーザーを渡す必要はないことに注目しましょう。Laravelが自動的にゲートクロージャにユーザーを渡します。To authorize an action using gates, you should use the allows
or denies
methods. 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:
if (Gate::allows('update-post', $post)) {
// 現在のユーザーはこのポストを更新できる
}
if (Gate::denies('update-post', $post)) {
// 現在のユーザーはこのポストを更新できない
}
特定のユーザーがあるアクションを実行できる認可を持っているかを確認するには、Gate
ファサードのforUser
メソッドを使用します。If you would like to determine if a particular 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)) {
// ユーザーはこのポストを更新できない
}
ゲートチェックのインターセプト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 callback that is run before all other authorization checks:
Gate::before(function ($user, $ability) {
if ($user->isSuperAdmin()) {
return true;
}
});
before
コールバックでNULL以外の結果を返すと、チェックの結果とみなされます。If the before
callback returns a non-null result that result will be considered the result of the check.
after
メソッドで、すべての認可チャックの後で実行されるコールバックを定義することも可能です。しかしながら、after
のコールバックから、認可チェックの結果を変更できません。You may use the after
method to define a callback to be executed after every authorization check. However, you may not modify the result of the authorization check from an after
callback:
Gate::after(function ($user, $ability, $result, $arguments) {
//
});
ポリシー作成Creating Policies
ポリシーの生成Generating Policies
ポリシーは特定のモデルやリソースに関する認可ロジックを系統立てるクラスです。たとえば、ブログアプリケーションの場合、Post
モデルとそれに対応する、ポストを作成/更新するなどのユーザーアクションを認可する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 Post
model and a corresponding 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[/docs/{{version}}/artisan]. 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
コマンドは空のポリシークラスを生成します。基本的な「CRUD」ポリシーメソッドを生成するクラスへ含めたい場合は、make:policy
コマンド実行時に--model
を指定してください。The make:policy
command will generate an empty policy class. If you would like to generate a class with the basic "CRUD" policy methods already included in the class, you may specify a --model
when executing the command:
php artisan make:policy PostPolicy --model=Post
サービスコンテナにより依存解決されるため、ポリシーのコンストラクタに必要な依存をタイプヒントすれば、自動的に注入されます。{tip} All 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.
">Tip!! 全ポリシーはLaravelの
ポリシーの登録Registering Policies
ポリシーができたら、登録する必要があります。インストールしたLaravelアプリケーションに含まれている、AuthServiceProvider
にはEloquentモデルと対応するポリシーをマップするためのpolicies
プロパティを含んでいます。ポリシーの登録とは、指定したモデルに対するアクションの認可時に、どのポリシーを利用するかをLaravelへ指定することです。Once the policy exists, it needs to be registered. The 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 model:
<?php
namespace App\Providers;
use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* アプリケーションにマップ付されたポリシー
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* アプリケーションの全認証/認可サービスの登録
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
ポリシーの記述Writing Policies
ポリシーのメソッドPolicy Methods
ポリシーが登録できたら、認可するアクションごとにメソッドを追加します。たとえば、指定したUser
が指定Post
インスタンスの更新をできるか決める、updata
メソッドをPostPolicy
に定義してみましょう。Once the policy 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 User
can update a given 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, for this example, let's verify that the user's id
matches the user_id
on the post:
<?php
namespace App\Policies;
use App\User;
use App\Post;
class PostPolicy
{
/**
* ユーザーにより指定されたポストが更新可能か決める
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
必要に応じ、様々なアクションを認可するために、追加のメソッドをポリシーに定義してください。たとえば、色々なPost
アクションを認可するために、view
やdelete
メソッドを追加できます。ただし、ポリシーのメソッドには好きな名前を自由につけられることを覚えておいてください。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
actions, but remember you are free to give your policy methods any name you like.
">Tip!! ポリシーを
--model
オプションを付け、Artisanコマンドにより生成した場合、view
、create
、update
、delete
アクションが含まれています。{tip} If you used the--model
option when generating your policy via the Artisan console, it will already contain methods for theview
,create
,update
, anddelete
actions.
モデルを持たないメソッドMethods Without Models
ポリシーメソッドの中には、現在の認証ユーザーのみを受け取り、認可するためのモデルを必要としないものもあります。この状況は、create
アクションを認可する場合に、よく現れます。たとえば、ブログを作成する場合、どんなポストかにはかかわらず、そのユーザーが作成可能かを認可したいでしょう。Some policy methods only receive the currently authenticated user and not an instance of the model they authorize. This situation is most common when authorizing create
actions. For example, if you are creating a blog, you may wish to check if a user is authorized to create any posts at all.
create
のように、モデルインスタンスを受け取らないポリシーメソッドを定義する場合は、モデルインスタンスを受け取る必要はありません。代わりに、その認証済みユーザーが期待している人物かをメソッドで定義してください。When defining policy methods that will not receive a model instance, such as a create
method, it will not receive a model instance. Instead, you should define the method as only expecting the authenticated user:
/**
* 指定されたユーザーがポストを作成できるかを決める
*
* @param \App\User $user
* @return bool
*/
public function create(User $user)
{
//
}
ポリシーフィルター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:
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
ユーザーに対して全認可を禁止したい場合は、before
メソッドからfalse
を返します。null
を返した場合、その認可の可否はポリシーメソッドにより決まります。If you would like to deny all authorizations for a user you should return false
from the before
method. If null
is returned, the authorization will fall through to the policy method.
Note:
クラスがチェックするアビリティと一致する名前のメソッドを含んでいない場合、ポリシークラスのbefore
メソッドは呼び出されません。{note} Thebefore
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
Userモデルによる確認Via The User Model
Laravelアプリケーションに含まれるUser
モデルは、アクションを認可するための便利な2つのメソッドを持っています。can
とcant
です。can
メソッドは認可したいアクションと関連するモデルを引数に取ります。例として、ユーザーが指定したPost
を更新を認可するかを決めてみましょう。The User
model that is included with your Laravel application includes two helpful methods for authorizing actions: can
and cant
. The can
method receives the action you wish to authorize and the relevant model. For example, let's determine if a user is authorized to update a given Post
model:
if ($user->can('update', $post)) {
//
}
指定するモデルのポリシーが登録済みであれば適切なポリシーの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 like create
may 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:
use App\Post;
if ($user->can('create', Post::class)) {
// 関連するポリシーの"create"メソッドが実行される
}
ミドルウェアによる認可Via Middleware
送信されたリクエストがルートやコントローラへ到達する前に、アクションを認可できるミドルウェアをLaravelは持っています。デフォルトでApp\Http\Kernel
クラスの中でcan
キーにIlluminate\Auth\Middleware\Authorize
ミドルウェアが割り付けられています。あるユーザーがブログポストを認可するために、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 blog post:
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// 現在のユーザーはこのポストを更新できる
})->middleware('can:update,post');
この例では、can
ミドルウェアへ2つの引数を渡しています。最初の引数は認可したいアクションの名前です。2つ目はポリシーメソッドに渡したいルートパラメータです。この場合、暗黙のモデル結合を使用しているため、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 Post
model will be passed to the policy method. If the user is not authorized to perform the given action, a HTTP response with a 403
status code will be generated by the middleware.
モデルを必要としないアクションActions That Don't Require Models
この場合も、create
のようなアクションではモデルインスタンスを必要としません。このようなケースでは、ミドルウェアへクラス名を渡してください。クラス名はアクションを認可するときに、どのポリシーを使用するかの判断に使われます。Again, some actions like create
may 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\Post');
コントローラヘルパによる認可Via Controller Helpers
User
モデルが提供している便利なメソッドに付け加え、App\Http\Controllers\Controller
ベースクラスを拡張しているコントローラに対し、Laravelはauthorize
メソッドを提供しています。can
メソッドと同様に、このメソッドは認可対象のアクション名と関連するモデルを引数に取ります。アクションが認可されない場合、authorize
メソッドはIlluminate\Auth\Access\AuthorizationException
例外を投げ、これはデフォルトでLaravelの例外ハンドラにより、403
ステータスコードのHTTPレスポンスへ変換されます。In addition to helpful methods provided to the User
model, Laravel provides a helpful authorize
method to any of your controllers which extend the App\Http\Controllers\Controller
base class. 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
, which the default Laravel exception handler will convert to an HTTP response with a 403
status code:
<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 指定したポストの更新
*
* @param Request $request
* @param Post $post
* @return 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 actions like create
may not require a model instance. In these situations, you may pass a class name to the authorize
method. The class name will be used to determine which policy to use when authorizing the action:
/**
* 新しいブログポストの生成
*
* @param Request $request
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request)
{
$this->authorize('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
family of directives:
@can('update', $post)
<!-- 現在のユーザーはポストを更新できる -->
@elsecan('create', App\Post::class)
<!-- 現在のユーザーはポストを作成できる -->
@endcan
@cannot('update', $post)
<!-- 現在のユーザーはポストを更新できない -->
@elsecannot('create', App\Post::class)
<!-- 現在のユーザーはポストを作成できない -->
@endcannot
これらのディレクティブは@if
や@unless
文を使う記述に対する、便利な短縮形です。上記の@can
と@cannot
文に対応するコードは以下のようになります。These directives are convenient shortcuts for writing @if
and @unless
statements. The @can
and @cannot
statements above respectively translate to the following statements:
@if (Auth::user()->can('update', $post))
<!-- 現在のユーザーはポストを更新できる -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- 現在のユーザーはポストを更新できない -->
@endunless
モデルを必要としないアクション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\Post::class)
<!-- 現在のユーザーはポストを更新できる -->
@endcan
@cannot('create', App\Post::class)
<!-- 現在のユーザーはポストを更新できない -->
@endcannot