Laravel 10.x 認可

イントロダクション

組み込み認証サービスの提供に加え、Laravelは特定のリソースに対するユーザーアクションを認可する手軽な方法も提供しています。たとえば、あるユーザーが認証されていても、アプリケーションが管理している特定のEloquentモデルまたはデータベースレコードを更新や削除する権限を持っていない場合があるでしょう。Laravelの認可機能は、こうしたタイプの認可チェックを管理するための簡単で組織化された方法を提供します。

Laravelは、アクションを認可する2つの主要な方法を提供します。ゲートポリシーです。ゲートとポリシーは、ルートやコントローラのようなものだと考えてください。ゲートは認可のためのクロージャベースのシンプルなアプローチを提供します。一方でポリシーはコントローラのように、特定のモデルやリソース周辺のロジックをひとかたまりにまとめます。このドキュメントでは、最初にゲートを説明し、その後でポリシーを見ていきましょう。

アプリケーションを構築するときに、ゲートのみを使用するか、ポリシーのみを使用するかを選択する必要はありません。ほとんどのアプリケーションには、ゲートとポリシーが混在する可能性が高く、それはまったく問題ありません。ゲートは、管理者ダッシュボードの表示など、モデルやリソースに関連しないアクションに最も適しています。対照的に、特定のモデルまたはリソースのアクションを認可する場合は、ポリシーを使用する必要があります。

ゲート

ゲートの作成

Warning!! ゲートは、Laravelの認可機能の基本を学ぶための優れた方法です。ただし、堅牢なLaravelアプリケーションを構築するときは、ポリシーを使用して認可ルールを整理することを検討する必要があります。

ゲートは、ユーザーが特定のアクションを実行することを許可されているかどうかを判断する単なるクロージャです。通常、ゲートは、Gateファサードを使用してApp\Providers\AuthServiceProviderクラスのbootメソッド内で定義されます。ゲートは常に最初の引数としてユーザーインスタンスを受け取り、オプションで関連するEloquentモデルなどの追加の引数を受け取る場合があります。

以下の例では、ユーザーが特定のApp\Models\Postモデルを更新できるかどうかを判断するためのゲートを定義します。ユーザーのidと、投稿を作成したユーザーのuser_idを比較することで、このゲートは可否を判定します。

use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Gate;

/**
 * 全認証/認可サービスの登録
 */
public function boot(): void
{
    Gate::define('update-post', function (User $user, Post $post) {
        return $user->id === $post->user_id;
    });
}

コントローラと同様に、ゲートもクラスコールバック配列を使用して定義できます。

use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;

/**
 * 全認証/認可サービスの登録
 */
public function boot(): void
{
    Gate::define('update-post', [PostPolicy::class, 'update']);
}

アクションの認可

ゲートを使用してアクションを認可するには、Gateファサードが提供するallowsdeniesメソッドを使用する必要があります。現在認証済みのユーザーをこれらのメソッドに渡す必要はないことに注意してください。Laravelは自動的にユーザーをゲートクロージャに引き渡します。認可が必要なアクションを実行する前に、アプリケーションのコントローラ内でゲート認可メソッドを呼び出すのが一般的です。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class PostController extends Controller
{
    /**
     * 指定した投稿を更新
     */
    public function update(Request $request, Post $post): RedirectResponse
    {
        if (! Gate::allows('update-post', $post)) {
            abort(403);
        }

        // 投稿を更新…

        return redirect('/posts');
    }
}

現在認証済みユーザー以外のユーザーがアクションの実行を許可されているかを確認する場合は、GateファサードでforUserメソッドを使用します。

if (Gate::forUser($user)->allows('update-post', $post)) {
    // ユーザーは投稿を更新可能
}

if (Gate::forUser($user)->denies('update-post', $post)) {
    // ユーザーは投稿を更新不可能
}

anyまたはnoneメソッドを使用して、一度に複数のアクション認可を確認できます。

if (Gate::any(['update-post', 'delete-post'], $post)) {
    // ユーザーは投稿を更新または削除可能
}

if (Gate::none(['update-post', 'delete-post'], $post)) {
    // ユーザーは投稿を更新または削除不可能
}

認可または例外を投げる

アクションを認可をチェックし、ユーザーが指定のアクションの実行を許可されていない場合は、Illuminate\Auth\Access\AuthorizationExceptionを自動で投げたい場合は、Gateファサードのauthorizeメソッドを使用します。AuthorizationExceptionのインスタンスは、Laravelの例外ハンドラによって自動的に403HTTPレスポンスへ変換されます。

Gate::authorize('update-post', $post);

// アクションは認可されている

追加コンテキストの提供

アビリティを認可するためのゲートメソッド(allowsdenischeckanynoneauthorizecancannot)と認可Bladeディレクティブ@can@cannot@canany)は、2番目の引数として配列を取れます。これらの配列要素は、パラメータとしてゲートクロージャに渡され、認可を決定する際の追加のコンテキストに使用できます。

use App\Models\Category;
use App\Models\User;
use Illuminate\Support\Facades\Gate;

Gate::define('create-post', function (User $user, Category $category, bool $pinned) {
    if (! $user->canPublishToGroup($category->group)) {
        return false;
    } elseif ($pinned && ! $user->canPinPosts()) {
        return false;
    }

    return true;
});

if (Gate::check('create-post', [$category, $pinned])) {
    // ユーザーは投稿を作成可能
}

ゲートのレスポンス

これまで、単純な論理値を返すゲートのみ見てきました。しかし、エラーメッセージなどのより詳細なレスポンスを返したい場合もあります。これには、ゲートからIlluminate\Auth\Access\Responseを返してください。

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メソッドを使用して、ゲートから返される完全な認可レスポンスを取得できます。

$response = Gate::inspect('edit-settings');

if ($response->allowed()) {
    // アクションは認可されている
} else {
    echo $response->message();
}

アクションが認可されていない場合にAuthorizationExceptionを投げるGate::authorizeメソッドを使用すると、認可レスポンスが提供するエラーメッセージがHTTPレスポンスへ伝播されます。

Gate::authorize('edit-settings');

// アクションは認可されている

HTTPレスポンスステータスのカスタマイズ

ゲートがアクションを拒否すると、403 HTTPレスポンスを返します。しかし場合により、別のHTTPステータスコードを返すほうが、便利なことがあります。認可チェックに失敗したときに返すHTTPステータスコードは、Illuminate\Auth\Access\ResponseクラスのdenyWithStatus静的コンストラクタを使用してカスタマイズできます。

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メソッドを提供しています。

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();
});

ゲートチェックの割り込み

特定のユーザーにすべての機能を付与したい場合があります。beforeメソッドを使用して、他のすべての認可チェックの前に実行するクロージャを定義できます。

use App\Models\User;
use Illuminate\Support\Facades\Gate;

Gate::before(function (User $user, string $ability) {
    if ($user->isAdministrator()) {
        return true;
    }
});

beforeクロージャがnull以外の結果を返した場合、その結果を許可チェックの結果とみなします。

afterメソッドを使用して、他のすべての認可チェックの後に実行されるクロージャを定義できます。

use App\Models\User;

Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {
    if ($user->isAdministrator()) {
        return true;
    }
});

beforeメソッドと同様に、afterクロージャがnull以外の結果を返した場合、その結果は認可チェックの結果とみなします。

インライン認可

時には、現在認証されているユーザーが、あるアクションを実行する認可を持っているかを、そのアクションに対応する専用のゲートを書かずに判断したいこともあるでしょう。Laravelでは、Gate::allowIfGate::denyIfメソッドを使い、「インライン」での認可チェックを行うことができます。

use App\Models\User;
use Illuminate\Support\Facades\Gate;

Gate::allowIf(fn (User $user) => $user->isAdministrator());

Gate::denyIf(fn (User $user) => $user->banned());

アクションが認可されていない場合や、現在認証されているユーザーがいない場合、Laravelは自動的にIlluminate\Auth\Access\AuthorizationExceptionという例外を投げます。AuthorizationExceptionのインスタンスは、Laravelの例外ハンドラが、自動的に403 HTTPレスポンスへ変換します。

ポリシーの作成

ポリシーの生成

ポリシーは、特定のモデルまたはリソースに関する認可ロジックを集めたクラスです。たとえば、アプリケーションがブログの場合、App\Models\Postモデルと投稿の作成や更新などのユーザーアクションを認可するためのPostモデルと対応するApp\Policies\PostPolicyがあるでしょう。

make:policy Artisanコマンドを使用してポリシーを生成できます。生成するポリシーはapp/Policiesディレクトリへ配置します。このディレクトリがアプリケーションに存在しない場合、Laravelが作成します。

php artisan make:policy PostPolicy

make:policyコマンドは、空のポリシークラスを生成します。リソースの表示、作成、更新、削除に関連するポリシーメソッドのサンプルを含んだクラスを生成する場合は、コマンドの実行時に--modelオプションを指定します。

php artisan make:policy PostPolicy --model=Post

ポリシーの登録

ポリシークラスを作成したら、登録する必要があります。ポリシーの登録とは、特定のモデルタイプに対するアクションを認可するときに、使用するポリシーをLaravelに指示する方法です。

新しいLaravelアプリケーションに含まれているApp\Providers\AuthServiceProviderには、Eloquentモデルを対応するポリシーにマップするpoliciesプロパティが含まれています。ポリシーを登録すると、特定のEloquentモデルに対するアクションを認可するときに使用するポリシーがLaravelに指示されます。

<?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,
    ];

    /**
     * 全アプリケーション認証/認可サービス登録
     */
    public function boot(): void
    {
        // ...
    }
}

ポリシーの自動検出

モデルポリシーを手作業で登録する代わりに、モデルとポリシーが標準のLaravel命名規約に従っている限り、Laravelはポリシーを自動的に検出できます。具体的にポリシーは、モデルを含むディレクトリが存在する階層より上のPoliciesディレクトリにある必要があります。したがって、たとえばモデルはapp/Modelsディレクトリに配置し、ポリシーはapp/Policiesディレクトリに配置する場合があるでしょう。この場合、Laravelはapp/Models/Policies、次にapp/Policiesのポリシーをチェックします。さらに、ポリシー名はモデル名と一致し、Policyサフィックスが付いている必要があります。したがって、UserモデルはUserPolicyポリシークラスに対応します。

独自のポリシー検出ロジックを定義する場合は、Gate::guessPolicyNamesUsingメソッドを使用してカスタムポリシー検出コールバックを登録できます。通常、このメソッドは、アプリケーションのAuthServiceProviderbootメソッドから呼び出す必要があります。

use Illuminate\Support\Facades\Gate;

Gate::guessPolicyNamesUsing(function (string $modelClass) {
    // 指定されたモデルに対するポリシークラスの名前を返す…
});

Warning!! AuthServiceProviderで明示的にマッピングされるポリシーは、自動検出される可能性のあるポリシーよりも優先されます。

ポリシーの作成

ポリシーメソッド

ポリシークラスを登録したら、認可するアクションごとにメソッドを追加できます。例として、あるApp\Models\UserがあるApp\Models\Postインスタンスを更新できるかどうかを決定するPostPolicyupdateメソッドを定義してみましょう。

updateメソッドは引数としてUserPostインスタンスを受け取り、そのユーザーが指定したPostを更新する権限があるかどうかを示すtrueまたはfalseを返す必要があります。したがって、この例では、ユーザーのidが投稿のuser_idと一致することを確認しています。

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    /**
     * 指定した投稿をユーザーが更新可能かを判定
     */
    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id;
    }
}

ポリシーが認可するさまざまなアクションの必要に合わせ、ポリシーに追加のメソッドをどんどん定義できます。たとえば、viewまたはdeleteメソッドを定義して、さまざまなPost関連のアクションを認可できますが、ポリシーメソッドには任意の名前を付けることができることを覚えておいてください。

Artisanコンソールを介してポリシーを生成するときに--modelオプションを使用した場合、はじめからviewAnyviewcreateupdatedeleterestoreforceDeleteアクションのメソッドが用意されます。

Note: すべてのポリシーはLaravelサービスコンテナを介して解決されるため、ポリシーのコンストラクターで必要な依存関係をタイプヒントして、自動的に依存注入することができます。

ポリシーのレスポンス

これまで、単純な論理値値を返すポリシーメソッドについてのみ説明してきました。しかし、エラーメッセージなどより詳細なレスポンスを返したい場合があります。これにはポリシーメソッドからIlluminate\Auth\Access\Responseインスタンスを返してください。

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;

/**
 * 指定された投稿をユーザーが更新可能か判定
 */
public function update(User $user, Post $post): Response
{
    return $user->id === $post->user_id
                ? Response::allow()
                : Response::deny('You do not own this post.');
}

ポリシーから認可レスポンスを返す場合でも、Gate::allowsメソッドは単純な論理値を返します。ただし、Gate::inspectメソッドを使用して、ゲートが返す完全な認可レスポンスを取得できます。

use Illuminate\Support\Facades\Gate;

$response = Gate::inspect('update', $post);

if ($response->allowed()) {
    // アクションは認可されている
} else {
    echo $response->message();
}

アクションが認可されていない場合にAuthorizationExceptionを投げるGate::authorizeメソッドを使用すると、認可レスポンスが提供するエラーメッセージがHTTPレスポンスへ伝播されます。

Gate::authorize('update', $post);

// アクションは認可されている

HTTPレスポンスステータスのカスタマイズ

ポリシーメソッドがアクションを拒否すると、403 HTTPレスポンスを返します。しかし場合により、別のHTTPステータスコードを返すほうが、便利なことがあります。認可チェックに失敗したときに返すHTTPステータスコードは、Illuminate\Auth\Access\ResponseクラスのdenyWithStatus静的コンストラクタを使用してカスタマイズできます。

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;

/**
 * 指定された投稿をユーザーが更新可能か判定
 */
public function update(User $user, Post $post): Response
{
    return $user->id === $post->user_id
                ? Response::allow()
                : Response::denyWithStatus(404);
}

404レスポンスによるリソースの隠蔽はウェブアプリケーションでは常套手段なため、使いやすいようにdenyAsNotFoundメソッドを提供しています。

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;

/**
 * 指定された投稿をユーザーが更新可能か判定
 */
public function update(User $user, Post $post): Response
{
    return $user->id === $post->user_id
                ? Response::allow()
                : Response::denyAsNotFound();
}

モデルのないメソッド

一部のポリシーメソッドは、現在認証済みユーザーのインスタンスのみを受け取ります。この状況は、createアクションを認可するばあいに頻繁に見かけます。たとえば、ブログを作成している場合、ユーザーが投稿の作成を認可されているかを確認したい場合があります。このような状況では、ポリシーメソッドはユーザーインスタンスのみを受け取る必要があります。

/**
 * 指定ユーザーが投稿を作成可能か確認
 */
public function create(User $user): bool
{
    return $user->role == 'writer';
}

ゲストユーザー

デフォルトでは、受信HTTPリクエストが認証済みユーザーによって開始されたものでない場合、すべてのゲートとポリシーは自動的にfalseを返します。ただし、「オプションの」タイプヒントを宣言するか、ユーザーの引数定義でnullのデフォルト値を指定することで、これらの認可チェックをゲートとポリシーに渡すことができます。

<?php

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    /**
     * 指定した投稿をユーザーが更新可能かを判定
     */
    public function update(?User $user, Post $post): bool
    {
        return $user?->id === $post->user_id;
    }
}

ポリシーフィルタ

ある特定のユーザーには、特定のポリシー内のすべてのアクションを認可したい場合があります。これには、ポリシーで「before」メソッドを定義します。beforeメソッドは、ポリシー上の他のメソッドの前に実行されるため、目的のポリシーメソッドが実際に呼び出される前にアクションを認可する機会に利用できます。この機能は、アプリケーション管理者にアクションの実行を許可するために最も一般的に使用されます。

use App\Models\User;

/**
 * 事前認可チェックの実行
 */
public function before(User $user, string $ability): bool|null
{
    if ($user->isAdministrator()) {
        return true;
    }

    return null;
}

特定のタイプのユーザー全員の認可チェックを拒否したい場合は、beforeメソッドからfalseを返してください。nullを返す場合は、認可チェックはポリシーメソッドへ委ねられます。

Warning!! ポリシークラスのbeforeメソッドは、チェックしている機能の名前と一致する名前のメソッドがクラスに含まれていない場合は呼び出されません。

ポリシーを使用したアクションの認可

ユーザーモデル経由

Laravelアプリケーションに含まれているApp\Models\Userモデルには、アクションを認可するための2つの便利なメソッドcancannotが含まれています。canメソッドとcannotメソッドは、認可するアクションの名前と関連するモデルを受け取ります。たとえば、ユーザーが特定のApp\Models\Postモデルを更新する権限を持っているかどうかを確認しましょう。通常、これはコントローラメソッド内で実行されます。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * 指定した投稿を更新
     */
    public function update(Request $request, Post $post): RedirectResponse
    {
        if ($request->user()->cannot('update', $post)) {
            abort(403);
        }

        // 投稿を更新…

        return redirect('/posts');
    }
}

指定したモデルのポリシーが登録されているの場合、canメソッドは自動的に適切なポリシーを呼び出し、論理値の結果を返します。モデルにポリシーが登録されていない場合、canメソッドは、指定されたアクション名に一致するクロージャベースのゲートを呼び出そうとします。

モデルを必要としないアクション

一部のアクションは、モデルインスタンスを必要としないcreateなどのポリシーメソッドに対応する場合があることに注意してください。このような状況では、クラス名をcanメソッドに渡すことができます。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * 投稿を作成
     */
    public function store(Request $request): RedirectResponse
    {
        if ($request->user()->cannot('create', Post::class)) {
            abort(403);
        }

        // 投稿を作成…

        return redirect('/posts');
    }
}

コントローラヘルパ経由

Laravelは、App\Models\Userモデルが提供する便利なメソッドに加えて、App\Http\Controllers\Controller基本クラスを拡張する任意のコントローラに役立つauthorizeメソッドを提供します。

canメソッドと同様に、このメソッドは、認可するアクションの名前とリレーションモデルを受け入れます。アクションが認可されていない場合、authorizeメソッドはIlluminate\Auth\Access\AuthorizationException例外を投げ、Laravel例外ハンドラは自動的に403ステータスコードのHTTPレスポンスに変換します。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * 指定したブログ投稿の更新
     *
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function update(Request $request, Post $post): RedirectResponse
    {
        $this->authorize('update', $post);

        // 現在のユーザーはこのブログ投稿を更新可能

        return redirect('/posts');
    }
}

モデルを必要としないアクション

すでに説明したように、createなどの一部のポリシーメソッドはモデルインスタンスを必要としません。このような状況では、クラス名をauthorizeメソッドに渡す必要があります。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。

use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

/**
 * 新しいブログ投稿の作成
 *
 * @throws \Illuminate\Auth\Access\AuthorizationException
 */
public function create(Request $request): RedirectResponse
{
    $this->authorize('create', Post::class);

    // 現在のユーザーはブログ投稿を作成可能

    return redirect('/posts');
}

リソースコントローラの認可

リソースコントローラを使用している場合は、コントローラのコンストラクターでauthorizeResourceメソッドを使用できます。このメソッドは、適切なcanミドルウェア定義をリソースコントローラのメソッドにアタッチします。

authorizeResourceメソッドは、最初の引数としてモデルのクラス名を受け入れ、2番目の引数としてモデルのIDを含むルート/リクエストパラメーターの名前を受け入れます。リソースコントローラ--modelフラグを使用して作成されていることを確認して、必要なメソッド引数とタイプヒントが含まれるようにしてください。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Post;

class PostController extends Controller
{
    /**
     * コントローラインスタンスの生成
     */
    public function __construct()
    {
        $this->authorizeResource(Post::class, 'post');
    }
}

以下のコントローラメソッドは、対応するポリシーメソッドにマップされています。リクエストが特定のコントローラメソッドにルーティングされると、コントローラメソッドが実行される前に、対応するポリシーメソッドが自動的に呼び出されます。

コントローラメソッド ポリシーメソッド
index viewAny
show view
create create
store create
edit update
update update
destroy delete

Note: make:policyコマンドを--modelオプションとともに使用し、特定のモデルのポリシークラスを手早く生成できます。php artisan make:policy PostPolicy --model=Post

ミドルウェア経由

Laravelには、受信リクエストがルートやコントローラに到達する前にアクションを認可できるミドルウェアが含まれています。デフォルトでは、Illuminate\Auth\Middleware\AuthorizeミドルウェアにはApp\Http\Kernelクラスのcanキーが割り当てられています。canミドルウェアを使用して、ユーザーが投稿を更新できることを認可する例を見てみましょう。

use App\Models\Post;

Route::put('/post/{post}', function (Post $post) {
    // 現在のユーザーは投稿を更新可能
})->middleware('can:update,post');

この例では、canミドルウェアに2つの引数を渡します。1つ目は認可するアクションの名前であり、2つ目はポリシーメソッドに渡すルートパラメーターです。この場合、暗黙のモデルバインディングを使用しているため、App\Models\Postモデルがポリシーメソッドに渡されます。ユーザーが特定のアクションを実行する権限を持っていない場合、ミドルウェアは403ステータスコードのHTTPレスポンスを返します。

これは簡単に、canメソッドを使い、canミドルウェアをルートへ指定できます。

use App\Models\Post;

Route::put('/post/{post}', function (Post $post) {
    // 現在のユーザーは投稿を更新可能
})->can('update', 'post');

モデルを必要としないアクション

繰り返しますが、createのようないくつかのポリシーメソッドはモデルインスタンスを必要としません。このような状況では、クラス名をミドルウェアに渡すことができます。クラス名は、アクションを認可するときに使用するポリシーを決定するために使用されます。

Route::post('/post', function () {
    // 現在のユーザーは投稿を作成可能
})->middleware('can:create,App\Models\Post');

ミドルウェア定義の中で、クラス名全体を文字列で指定するのは面倒です。そのため、canメソッドを使って、canミドルウェアをルートへ指定できます。

use App\Models\Post;

Route::post('/post', function () {
    // 現在のユーザーは投稿を作成可能
})->can('create', Post::class);

Bladeテンプレート経由

Bladeテンプレートを作成するとき、ユーザーが特定のアクションを実行する許可がある場合にのみ、ページの一部を表示したい場合があります。たとえば、ユーザーが実際に投稿を更新できる場合にのみ、ブログ投稿の更新フォームを表示したい場合があります。この状況では、@canおよび@cannotディレクティブを使用できます。

@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ステートメントは、以下のステートメントと同等です。

@if (Auth::user()->can('update', $post))
    <!-- 現在のユーザーは投稿を更新可能 -->
@endif

@unless (Auth::user()->can('update', $post))
    <!-- 現在のユーザーは投稿を更新不可能 -->
@endunless

また、ユーザーが複数のアクションの実行を認可されているかを判定することもできます。これには、@cananyディレクティブを使用します。

@canany(['update', 'view', 'delete'], $post)
    <!-- 現在のユーザーは、投稿を更新、表示、削除可能 -->
@elsecanany(['create'], \App\Models\Post::class)
    <!-- 現在のユーザーは投稿を作成可能 -->
@endcanany

モデルを必要としないアクション

他のほとんどの認可メソッドと同様に、アクションがモデルインスタンスを必要としない場合は、クラス名を@canおよび@cannotディレクティブに渡すことができます。

@can('create', App\Models\Post::class)
    <!-- 現在のユーザーは投稿を作成可能 -->
@endcan

@cannot('create', App\Models\Post::class)
    <!-- 現在のユーザーは投稿を作成不可能 -->
@endcannot

追加コンテキストの提供

ポリシーを使用してアクションを認可する場合、2番目の引数としてさまざまな認可関数とヘルパに配列を渡すことができます。配列の最初の要素は、呼び出すポリシーを決定するために使用され、残りの配列要素は、パラメーターとしてポリシーメソッドに渡され、認可の決定を行う際の追加のコンテキストに使用できます。たとえば、追加の$categoryパラメータを含む次のPostPolicyメソッド定義について考えてみます。

/**
 * 指定された投稿をユーザーが更新可能か判定
 */
public function update(User $user, Post $post, int $category): bool
{
    return $user->id === $post->user_id &&
           $user->canUpdateCategory($category);
}

認証済みユーザーが特定の投稿を更新できるか判断する場合、次のようにこのポリシーメソッドを呼び出すことができます。

/**
 * 指定ブログ投稿を更新
 *
 * @throws \Illuminate\Auth\Access\AuthorizationException
 */
public function update(Request $request, Post $post): RedirectResponse
{
    $this->authorize('update', [$post, $request->category]);

    // 現在のユーザーはブログ投稿を更新可能

    return redirect('/posts');
}

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる