イントロダクションIntroduction
初めから用意されている認証サービスに付け加え、Laravelは認可ロジックを取りまとめ、リソースへのアクセスをコントロールする簡単な手段を提供します。認可ロジックを組織立てるのに役立つメソッドやヘルパはたくさん用意されていますので、このドキュメントで紹介します。In addition to providing authentication[/docs/{{version}}/authentication] services out of the box, Laravel also provides a simple way to organize authorization logic and control access to resources. There are a variety of methods and helpers to assist you in organizing your authorization logic, and we'll cover each of them in this document.
注意: 認可機能はLaravel 5.1.11で追加されました。この機能をアプリケーションに統合する前に、アップグレードガイドを参照してください。Note: Authorization was added in Laravel 5.1.11, please refer to the upgrade guide[/docs/{{version}}/upgrade] before integrating these features into your application.
アビリティの定義Defining Abilities
あるユーザーが指定されたアクションを実行しても良いかをシンプルに判定するには、Illuminate\Auth\Access\Gate
クラスを使い「アビリティ(ability)」を定義してください。Laravelに初めから用意されているAuthServiceProvider
は、アプリケーションの全アビリティを定義するために便利な場所です。例として現在のUser
とPost
モデルを受け取る、update-post
アビリティを定義してみましょう。このアビリティの中で、ユーザーのid
がポストのuser_id
と一致するかを判定します。The simplest way to determine if a user may perform a given action is to define an "ability" using the Illuminate\Auth\Access\Gate
class. The AuthServiceProvider
which ships with Laravel serves as a convenient location to define all of the abilities for your application. For example, let's define an update-post
ability which receives the current User
and a Post
model[/docs/{{version}}/eloquent]. Within our ability, we will determine if the user's id
matches the post's user_id
:
<?php
namespace App\Providers;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* 全認証/認可サービスの登録
*
* @param \Illuminate\Contracts\Auth\Access\Gate $gate
* @return void
*/
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
$gate->define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
}
}
渡ってきた$user
がNULL
ではないかの、チェックを行っていないことに注目です。Gate
はユーザーが認証されていないか、forUser
メソッドを使いユーザーが指定されていない場合は、全アビリティから自動的にfalse
を返します。Note that we did not check if the given $user
is not NULL
. The Gate
will automatically return false
for all abilities when there is not an authenticated user or a specific user has not been specified using the forUser
method.
クラスベースのアビリティClass Based Abilities
認可のコールバックとして「クロージャー」を登録する方法に加え、クラス名とメソッドの文字列を引数に渡してもクラスメソッドを登録できます。必要であれば、クラスはサービスコンテナを利用し、依存解決されます。In addition to registering Closures
as authorization callbacks, you may register class methods by passing a string containing the class name and the method. When needed, the class will be resolved via the service container[/docs/{{version}}/container]:
$gate->define('update-post', 'Class@method');
認可チェックの停止Intercepting Authorization Checks
場合により、特定のユーザーに対しては全アビリティーを許可したい場合があります。この場合は他の全認可チェックの前に実行されるコールバックを定義するbefore
メソッドを使ってください。Sometimes, you may wish to grant all abilities to a specific user. For this situation, 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) {
//
});
アビリティーの確認Checking Abilities
Gateファサードによる確認Via The Gate Facade
アビリティーを定義したら、さまざまな方法で「確認」できます。最初はGate
ファサードのcheck
、allow
、denies
メソッドを使う方法です。これらのメソッドはアビリティ名とコールバックに渡した引数を受け取ります。Gate
が自動的に現在のユーザーをコールバック渡す引数の先頭に付け加えるため、こうしたメソッドに現在のユーザーを渡す必要はありません。ですから既に定義したupdate-post
アビリティーを確認する場合、denies
メソッドにはPost
インスタンスを渡す必要があるだけです。Once an ability has been defined, we may "check" it in a variety of ways. First, we may use the check
, allows
, or denies
methods on the Gate
facade[/docs/{{version}}/facades]. All of these methods receive the name of the ability and the arguments that should be passed to the ability's callback. You do not need to pass the current user to these methods, since the Gate
will automatically prepend the current user to the arguments passed to the callback. So, when checking the update-post
ability we defined earlier, we only need to pass a Post
instance to the denies
method:
<?php
namespace App\Http\Controllers;
use Gate;
use App\User;
use App\Post;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 指定したポストの更新
*
* @param int $id
* @return Response
*/
public function update($id)
{
$post = Post::findOrFail($id);
if (Gate::denies('update-post', $post)) {
abort(403);
}
// ポストの更新処理…
}
}
当然のことながら、allows
メソッドはdenies
メソッドをただひっくり返した働きをし、アクションが認可されていればtrue
を返します。check
メソッドはallows
メソッドのエイリアスです。Of course, the allows
method is simply the inverse of the denies
method, and returns true
if the action is authorized. The check
method is an alias of the allows
method.
特定のユーザーに対するアビリティーを確認Checking Abilities For Specific Users
現在認証されているユーザーではなく、別のユーザーが指定したアビリティーを持っているかをGate
ファサードで確認したい場合は、forUser
メソッドを使います。If you would like to use the Gate
facade to check if a user other than the currently authenticated user has a given ability, you may use the forUser
method:
if (Gate::forUser($user)->allows('update-post', $post)) {
//
}
複数の引数の指定Passing Multiple Arguments
もちろんアビリティのコールバックには複数の引数が指定できます。Of course, ability callbacks may receive multiple arguments:
Gate::define('delete-comment', function ($user, $post, $comment) {
//
});
アビリティーで複数の引数が必要であれば、Gate
ファサードのメソッドに引数を配列として渡してください。If your ability needs multiple arguments, simply pass an array of arguments to the Gate
methods:
if (Gate::allows('delete-comment', [$post, $comment])) {
//
}
Userモデルによる確認Via The User Model
他のやり方として、アビリティーをUser
モデルインスタンスでも確認できます。LaravelのApp\User
モデルは、can
とcannot
メソッドを提供しているAuthorizable
トレイトをuseしています。これらのメソッドは、Gate
ファサードのallow
とdenies
メソッドと使い方が似ています。では、前の例と同様に、コードを次のように変更してみましょう。Alternatively, you may check abilities via the User
model instance. By default, Laravel's App\User
model uses an Authorizable
trait which provides two methods: can
and cannot
. These methods may be used similarly to the allows
and denies
methods present on the Gate
facade. So, using our previous example, we may modify our code like so:
<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 指定したポストの更新
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return Response
*/
public function update(Request $request, $id)
{
$post = Post::findOrFail($id);
if ($request->user()->cannot('update-post', $post)) {
abort(403);
}
// ポストの更新処理…
}
}
もちろん、can
メソッドは単にcannot
メソッドの真反対の働きです。Of course, the can
method is simply the inverse of the cannot
method:
if ($request->user()->can('update-post', $post)) {
// Update Post...
}
Bladeテンプレートでの確認Within Blade Templates
現在の認証ユーザーが指定したアビリティーを持っているかを簡単に確認するのに便利なように、Laravelは@can
Bladeディレクティブを用意しています。例を見てください。For convenience, Laravel provides the @can
Blade directive to quickly check if the currently authenticated user has a given ability. For example:
<a href="/post/{{ $post->id }}">ポスト表示</a>
@can('update-post', $post)
<a href="/post/{{ $post->id }}/edit">ポスト編集</a>
@endcan
@can
ディレクティブは、@else
ディレクティブと組み合わせても使えます。You may also combine the @can
directive with @else
directive:
@can('update-post', $post)
<!-- 現在のユーザーはポストを更新できる -->
@else
<!-- 現在のユーザーはポストを更新できない -->
@endcan
フォームリクエストでの確認Within Form Requests
Gate
で定義したアビリティーをフォームリクエストのauthorize
メソッドで活用する選択を取ることもできます。You may also choose to utilize your Gate
defined abilities from a form request's[/docs/{{version}}/validation#form-request-validation] authorize
method. For example:
/**
* ユーザーがこのリクエストを作成できる認可があるかの判定
*
* @return bool
*/
public function authorize()
{
$postId = $this->route('post');
return Gate::allows('update', Post::findOrFail($postId));
}
ポリシーPolicies
ポリシーの作成Creating Policies
全認可ロジックをAuthServiceProvider
の中で定義するのは、大きなアプリケーションでは厄介ですから、Laravelでは認可ロジックを「ポリシー」クラスに分割できます。ポリシーは普通のPHPクラスで、認可するリソースに基づいてロジックをグループ分けするものです。Since defining all of your authorization logic in the AuthServiceProvider
could become cumbersome in large applications, Laravel allows you to split your authorization logic into "Policy" classes. Policies are plain PHP classes that group authorization logic based on the resource they authorize.
始めにPost
モデルの認可を管理するポリシーを生成しましょう。make:policy
Artisanコマンドでポリシーを生成します。生成したポリシーはapp/Policies
ディレクトリーへ設置されます。First, let's generate a policy to manage authorization for our Post
model. 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:
php artisan make:policy PostPolicy
ポリシーの登録Registering Policies
ポリシーができたら、Gate
クラスで登録する必要があります。AuthServiceProvider
には様々なエンティティを管理するポリシーとマップするためのpolicies
プロパティを含んでいます。では、Post
モデルのポリシーであるPostPolicy
クラスを指定しましょう。Once the policy exists, we need to register it with the Gate
class. The AuthServiceProvider
contains a policies
property which maps various entities to the policies that manage them. So, we will specify that the Post
model's policy is the PostPolicy
class:
<?php
namespace App\Providers;
use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* アプリケーションにマップするポリシー
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* アプリケーションの全認証/認可サービスを登録
*
* @param \Illuminate\Contracts\Auth\Access\Gate $gate
* @return void
*/
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
}
}
ポリシーの記述Writing Policies
ポリシーを生成し登録したら、認可する各アビリティーのためのメソッドを追加できます。指定したUser
がPost
を「更新(update)」できるかを判定する、update
メソッドをPostPolicy
に例として定義してみます。Once the policy has been generated and registered, we can add methods for each ability it authorizes. For example, let's define an update
method on our PostPolicy
, which will determine if the given User
can "update" a 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;
}
}
認可する様々なアビリティーを必要なだけポリシーにメソッドとして追加定義してください。たとえばshow
やdestroy
、addComment
メソッドなど、多様なPost
アクションの認可が定義できるでしょう。You may continue to define additional methods on the policy as needed for the various abilities it authorizes. For example, you might define show
, destroy
, or addComment
methods to authorize various Post
actions.
注目: 全ポリシーはLaravelのサービスコンテナにより依存解決されます。つまりポリシーのコンストラクターに必要な依存をタイプヒントで指定すれば、自動的に挿入されます。Note: All policies are resolved via the Laravel service container[/docs/{{version}}/container], meaning you may type-hint any needed dependencies in the policy's constructor and they will be automatically injected.
全チェックの停止Intercepting All Checks
場合により特定のユーザーにポリシーの全アビリティーを許可したい場合があります。この状況ではポリシーにbefore
メソッドを定義してください。このメソッドはポリシーにある他の全認可チェックより先に実行されます。Sometimes, you may wish to grant all abilities to a specific user on a policy. For this situation, define a before
method on the policy. This method will be run before all other authorization checks on the policy:
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
before
メソッドがnullでない値を返した場合、それをチェックの結果として取り扱います。If the before
method returns a non-null result that result will be considered the result of the check.
ポリシーの確認Checking Policies
ポリシーメソッドはクロージャーベースの認可コールバックと全く同じ方法で呼び出します。Gate
ファサードやUser
モデル、@can
Bladeディレクティブ、policy
ヘルパを使用できます。Policy methods are called in exactly the same way as Closure
based authorization callbacks. You may use the Gate
facade, the User
model, the @can
Blade directive, or the policy
helper.
Gateファサードによる確認Via The Gate Facade
Gate
はメソッドに渡された引数のクラスを調べ、どのポリシーを使用するか自動的に決定します。ですからPost
インスタンスをdenies
メソッドに渡せば、Gate
は認可するアクションに合ったPostPolicy
を使用します。The Gate
will automatically determine which policy to use by examining the class of the arguments passed to its methods. So, if we pass a Post
instance to the denies
method, the Gate
will utilize the corresponding PostPolicy
to authorize actions:
<?php
namespace App\Http\Controllers;
use Gate;
use App\User;
use App\Post;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 指定ポストの更新
*
* @param int $id
* @return Response
*/
public function update($id)
{
$post = Post::findOrFail($id);
if (Gate::denies('update', $post)) {
abort(403);
}
// ポストの更新処理…
}
}
Userモデルによる確認Via The User Model
User
モデルのcan
とcannot
メソッドも引数に指定された引数に対する使用可能なポリシーがあれば、自動的に使用します。これらのメソッドはアプリケーションが取得したUser
インスタンス全てに対するアクションを認可するために、便利な手法を提供しています。The User
model's can
and cannot
methods will also automatically utilize policies when they are available for the given arguments. These methods provide a convenient way to authorize actions for any User
instance retrieved by your application:
if ($user->can('update', $post)) {
//
}
if ($user->cannot('update', $post)) {
//
}
Bladeテンプレートによる確認Within Blade Templates
同様に、@can
Bladeディレクティブも与えられた引数に対して使用可能なポリシーを活用します。Likewise, the @can
Blade directive will utilize policies when they are available for the given arguments:
@can('update', $post)
<!-- 現在のユーザーはポストを更新できる -->
@endcan
policyヘルパによる確認Via The Policy Helper
グローバルなpolicy
ヘルパ関数は、指定されたクラスインスタンスに対する「ポリシー」クラスを取得するために使用します。例えば、Post
インスタンスをpolicy
ヘルパに渡し、対応するPostPolicy
クラスのインスタンスを取得できます。The global policy
helper function may be used to retrieve the Policy
class for a given class instance. For example, we may pass a Post
instance to the policy
helper to get an instance of our corresponding PostPolicy
class:
if (policy($post)->update($user, $post)) {
//
}
コントローラーの認可Controller Authorization
Laravelに含まれるデフォルトのApp\Http\Controllers\Controller
基本クラスでは、AuthorizesRequests
トレイトがuseされています。このトレイトはauthorize
メソッドを提供しており、簡単に指定アクションを認可するために使用でき、アクションが認可されていなければHttpException
を投げます。By default, the base App\Http\Controllers\Controller
class included with Laravel uses the AuthorizesRequests
trait. This trait provides the authorize
method, which may be used to quickly authorize a given action and throw a HttpException
if the action is not authorized.
authorize
メソッドはGate::allows
や$user->can()
などの認可メソッドと同じ使用方法です。では、Post
を更新するリクエストを手っ取り早く認可するために、authorize
メソッドを用いてみましょう。The authorize
method shares the same signature as the various other authorization methods such as Gate::allows
and $user->can()
. So, let's use the authorize
method to quickly authorize a request to update a Post
:
<?php
namespace App\Http\Controllers;
use App\Post;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 指定ポストの更新
*
* @param int $id
* @return Response
*/
public function update($id)
{
$post = Post::findOrFail($id);
$this->authorize('update', $post);
// ポストの更新処理…
}
}
アクションが認可されていれば、コントローラーは通常通り続けて実行されます。しかしauthorize
メソッドがアクションを非認可と判断すると、HttpException
が自動的に投げられ、 403 Not Authorized
ステータスコードのHTTPレスポンスが生成されます。ご覧の通りにauthorize
メソッドはコード1行でアクションを認可し、例外を投げるための便利で手っ取り早い方法です。If the action is authorized, the controller will continue executing normally; however, if the authorize
method determines that the action is not authorized, a HttpException
will automatically be thrown which generates a HTTP response with a 403 Not Authorized
status code. As you can see, the authorize
method is a convenient, fast way to authorize an action or throw an exception with a single line of code.
AuthorizesRequests
トレイトは、現在認証中ではない別のユーザーのアクションを認可する、authorizeForUser
メソッドも提供しています。The AuthorizesRequests
trait also provides the authorizeForUser
method to authorize an action on a user that is not the currently authenticated user:
$this->authorizeForUser($user, 'update', $post);
ポリシーメソッドの自動決定Automatically Determining Policy Methods
ポリシーのメソッドはコントローラーのメソッドと頻繁に対応します。たとえば前記のupdate
メソッドのように、update
と言う名前がコントローラーメソッドとポリシーメソッドで共通です。Frequently, a policy's methods will correspond to the methods on a controller. For example, in the update
method above, the controller method and the policy method share the same name: update
.
そのため、Laravelはauthorize
メソッドの引数にインスタンスだけを渡すことも許しています。認可するアビリティは呼び出しているメソッドの名前を元に自動的に決められます。この例では、コントローラーのupdate
メソッドからauthorize
が呼びだされていますから、PostPolicy
上でもupdate
メソッドが呼びだされます。For this reason, Laravel allows you to simply pass the instance arguments to the authorize
method, and the ability being authorized will automatically be determined based on the name of the calling function. In this example, since authorize
is called from the controller's update
method, the update
method will also be called on the PostPolicy
:
/**
* 指定ポストの更新
*
* @param int $id
* @return Response
*/
public function update($id)
{
$post = Post::findOrFail($id);
$this->authorize($post);
// ポストの更新…
}