イントロダクション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.
アビリティの定義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
App\Http\Controllers\Controller
ベースクラスはデフォルト状態で、Laravelが利用するAuthorizesRequests
トレイトを含んでいます。このトレイトは指定したアクションを簡単に認可するためのauthorize
メソッドを持っており、そのアクションを認可できない場合は、AuthorizationException
例外を投げます。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 AuthorizationException
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
メソッドがアクションを非認可と判断すると、AuthorizationException
が自動的に投げられ、
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
AuthorizationException
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);
// ポストの更新…
}