bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. Laravelのcan()メソッドの動き整理

Laravelのcan()メソッドの動き整理

Mar 13, 2026 Laravel bucket-sort

Laravel の認可処理を見直していて、$user->can() という書き方が改めて分かりやすいと感じました。

「このユーザーはこの操作をしてよいか?」 という意味が、そのままコードに表れているからです。

特に FormRequest の authorize() と組み合わせると、認可の意図がかなり読みやすくなるので、自分用の整理としてまとめておきます。

例:FormRequest での can() の使い方

例えば、更新リクエストを受け取る FormRequest が次のように書かれているとします。

class RecipientUpdateRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('update', $this->route('recipient'));
    }
}

これ、かなり自然に読めます。

  • this->user() → 現在ログインしているユーザー

  • can('update', ...) → このユーザーはこのデータを更新できる?

つまり、

「現在のユーザーに更新権限があるなら、このリクエストを通す」

という意味になります。

can() は authorize() を再帰的に呼んでいるわけではない

最初に少し気になったのがここです。

FormRequest::authorize() の中で can() を呼んでいるので、 ぱっと見では「認可判定の中でまた認可判定している?」ようにも見えます。

でも実際には違います。

$user->can() は FormRequest::authorize() を呼び直すのではなく、 Laravel の Gate を通じて Policy を呼び出すメソッドです。

処理の流れを簡単に書くとこうなります。

FormRequest::authorize()
  └─ $this->user()->can('update', $recipient)
       └─ Gate::check('update', $recipient)
            └─ RecipientPolicy::update(User $user, Recipient $recipient)
                 └─ 判定結果を返す

つまり authorize() は、 Gate に問い合わせて、その結果をそのまま返しているだけ という構造です。

それぞれの役割

少し整理しておくと、各要素の役割はこんな感じです。

$this->user()

現在ログインしているユーザーを取得します。

認可の世界では

「誰が操作しようとしているか」

を表します。

$user->can('update', $recipient)

ここが認可チェックの入口です。

can() は

  • 何の操作をしたいのか
  • どの対象に対して行うのか

を渡して、許可されているかを判定します。

この書き方の良いところは、主語がユーザーになっていることです。

$user->can('view', $document)
$user->can('update', $recipient)
$user->can('delete', $post)

「ユーザーはそれをできるのか?」 という読み方がそのままできます。

Policy が呼ばれる

Recipient モデルに対応する Policy が登録されていれば、 Laravel は自動的にそのメソッドを呼びます。

例えば次のようなものです。

class RecipientPolicy
{
    public function update(User $user, Recipient $recipient): bool
    {
        return $user->corp_id === $recipient->corp_id;
    }
}

つまり

can('update', $recipient)

は最終的に

RecipientPolicy::update($user, $recipient)

を呼ぶための入口になります。

authorize() と can() の関係

役割を整理するとこうなります。

メソッド 役割
FormRequest::authorize() このリクエストを通してよいか判定
$user->can() / Gate 認可ロジック本体(Policy を呼ぶ)
$this->authorize() (Controller) 認可チェックして NG なら例外

ポイントは、

authorize() 自体は認可ロジックの本体ではない

ということです。

authorize() は 「このリクエストを受け付けていいですか?」 という入口のチェック場所です。

コントローラー側の認可と重複することがある

同じ認可をコントローラーで書くこともあります。

public function update(RecipientUpdateRequest $request, Recipient $recipient)
{
    $this->authorize('update', $recipient);

    // 更新処理
}

これはもちろん正しいです。

ただし、すでに FormRequest 側で認可しているなら コントローラー側の認可は重複になります。

public function update(RecipientUpdateRequest $request, Recipient $recipient)
{
    // 認可済み
}

この形にすると、コントローラーが少しすっきりします。

Request で認可するか、Controller で認可するか

これは好みや設計にもよりますが、自分の整理ではこんな感じです。

FormRequest に書くと良いケース

  • リクエスト単位で完結する認可
  • バリデーションと同じ入口で弾きたい
  • コントローラーをシンプルにしたい

Controller に書くと良いケース

  • 処理の途中で認可が必要
  • 条件によって認可対象が変わる
  • 複数の認可を段階的に行う

can() はかなり読みやすい

今回改めて思ったのは、

$user->can('update', $recipient)

という書き方は、かなり直感的です。

認可ロジックの中身は Policy に書くとして、 呼び出し側では

「ユーザーはこの操作をできる?」

という表現だけ書けばよい。

認可は if 文を書き始めるとすぐ散らかるので、 入口を can() に揃えるのはやはり良い設計だと思いました。

まとめ

今回整理したポイントです。

  • can() は Laravel の Gate を呼び出す
  • Gate は 対応する Policy を探して実行する
  • FormRequest::authorize() は その結果を返す場所
  • authorize() の中で can() を呼んでも再帰にはならない
  • Request で認可するなら Controller の認可を省けることもある

Laravel の認可は、最初は少し分かりにくいですが、

「user → can → Gate → Policy」

という流れを覚えると、かなり整理しやすくなります。

Laravel Can Gate Policy FormRequest Authorize 認可 PHP
← Laravel FormRequestのauthorize()をちゃんと書くべき理由 Livewireのファイルアップロード一時ファイルは誰が掃除しているのか →

Related Posts

  • Laravel FormRequestのauthorize()をちゃんと書くべき理由 Mar 12, 2026
  • Laravelで用意されている認可(Authorization)の仕組みと使いどころ Mar 9, 2026
  • Laravel の Event / Listener で Pub/Sub を実装する Apr 2, 2026
  • PHP/Laravel で値の状態を判定するヘルパ関数まとめ Mar 30, 2026

Table of Contents

  • 例:FormRequest での can() の使い方
  • can() は authorize() を再帰的に呼んでいるわけではない
  • それぞれの役割
    • $this->user()
    • $user->can('update', $recipient)
    • Policy が呼ばれる
  • authorize() と can() の関係
  • コントローラー側の認可と重複することがある
  • Request で認可するか、Controller で認可するか
    • FormRequest に書くと良いケース
    • Controller に書くと良いケース
  • can() はかなり読みやすい
  • まとめ

Recent Posts

  • Laravel の Event / Listener で Pub/Sub を実装する Apr 2, 2026
  • [C#] delegate と event の仕組みを整理する Apr 1, 2026
  • Pub/Sub パターンとは何か Mar 31, 2026
  • PHP/Laravel で値の状態を判定するヘルパ関数まとめ Mar 30, 2026
  • Filament の dehydrated メソッドとは何か Mar 29, 2026

Categories

  • AWS27
  • C#22
  • .NET20
  • Laravel16
  • Linux12
  • Apache8
  • MySQL8
  • PHP8
  • DynamoDB6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • セキュリティ3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • AWS
  • C#
  • .NET
  • Laravel
  • PHP
  • MySQL
  • セキュリティ
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • DoS
  • Nginx
  • Windows
  • WordPress
  • パフォーマンス
  • 監視
  • Amazon Linux 2023
  • CMS
  • Docker
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • 認可
  • Aurora
  • Blade
Powered by Hugo & Explore Theme.