イントロダクション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);
// ポストの更新…
}