Webアプリケーションでは、「誰がどの操作をしてよいか」 を制御する仕組みが必要になります。 これが 認可 (Authorization) です。
例えば次のようなケースです。
/orders/{id}で注文履歴を表示する- しかし 他人の注文履歴は見れてはいけない
- 注文者本人だけ閲覧できるようにする
Laravelでは、このような認可を実装するためにいくつかの仕組みが用意されています。 この記事では、それぞれの仕組みと使いどころを整理します。
まずは素朴な実装(if文)
最も単純な方法は、コントローラでユーザーIDを比較することです。
public function show(string $id)
{
$order = Order::findOrFail($id);
if ($order->user_id !== auth()->id()) {
abort(403);
}
return view('orders.show', compact('order'));
}
これはシンプルで分かりやすく、問題なく動きます。
しかしアプリケーションが大きくなると、次の問題が起きがちです。
- 同じ認可ロジックが 複数のコントローラに散らばる
- 認可ルールが 変更されたとき修正箇所が多くなる
- コードの可読性が下がる
そこでLaravelでは、認可ロジックを整理するための仕組みが提供されています。
Laravelの認可の仕組み
Laravelでは主に次の仕組みが用意されています。
| 仕組み | 用途 |
|---|---|
| Policy | モデル単位の認可ルール |
| Gate | シンプルな権限チェック |
| authorize() | コントローラ内で認可 |
| can middleware | ルートレベルで認可 |
| FormRequest authorize() | 入力処理と一緒に認可 |
| Blade @can | UI表示制御 |
それぞれ役割が少しずつ違います。
Policy(ポリシー)
Policyは モデル単位の認可ルールをまとめる仕組みです。
例えば OrderPolicy を作ると、
- 注文を閲覧できるか
- 注文を更新できるか
- 注文を削除できるか
といったルールを1箇所にまとめられます。
例:
class OrderPolicy
{
public function view(User $user, Order $order)
{
return $order->user_id === $user->id;
}
}
そしてコントローラでは次のように書きます。
public function show(Order $order)
{
$this->authorize('view', $order);
return view('orders.show', compact('order'));
}
これで
「このユーザーはこの注文を閲覧できるか」
を自動的に判定してくれます。
Policyのメリット
- 認可ルールを 1箇所に集約できる
- コードの再利用性が高い
- 仕様変更に強い
Laravelの認可では、Policyがもっとも基本的な仕組みです。
Gate(ゲート)
Gateは 単純な権限チェックを定義する仕組みです。
Policyは「モデルに対する操作」を扱うのに対して、Gateはもう少し一般的な権限チェックに向いています。
例:
Gate::define('view-admin-page', function ($user) {
return $user->is_admin;
});
使用例:
if (Gate::allows('view-admin-page')) {
// 管理画面表示
}
Gateの使いどころ
- 管理画面に入れるか
- 特定機能を使えるか
など、特定のモデルに依存しない権限チェックです。
authorize()(コントローラ内認可)
コントローラ内で認可チェックする方法です。
$this->authorize('view', $order);
認可が失敗すると 自動で403エラーになります。
使いどころ
- コントローラ内で明示的に認可したい
- 処理の途中で認可チェックしたい
can middleware(ルートレベル認可)
ルート定義で認可を指定することもできます。
Route::get('/orders/{order}', [OrderController::class, 'show'])
->middleware('can:view,order');
これにより
- 認可に失敗した場合は、コントローラに入る前に403
になります。
メリット
- ルートを見れば必要な権限が分かる
- 不要な処理を実行しない
FormRequestの authorize()
バリデーション用のFormRequestには、認可メソッドがあります。
public function authorize()
{
return $this->user()->id === $this->order->user_id;
}
ここで false を返すと処理は拒否されます。
使いどころ
- 更新処理
- 作成処理
など、入力バリデーションと認可をまとめたい場合です。
Bladeの @can
ビュー側では次のディレクティブが使えます。
@can('update', $order)
<button>編集</button>
@endcan
これは
「編集権限があるユーザーだけボタンを表示する」
という用途です。
ただし重要な点として
UIで隠すだけではセキュリティにはならない
ため、サーバー側の認可チェックも必ず必要です。
どの仕組みを使うべきか
実務では次の組み合わせがよく使われます。
| 方法 | 用途 |
|---|---|
| Policy | モデルの認可ルール |
| authorize() | コントローラ内認可 |
| can middleware | ルートレベル認可 |
| Gate | モデルに依存しない権限 |
特に
Policy + authorize()
の組み合わせが最も一般的です。
まとめ
Laravelには認可のための複数の仕組みが用意されています。
| 仕組み | 主な用途 |
|---|---|
| Policy | モデル単位の認可 |
| Gate | シンプルな権限チェック |
| authorize() | コントローラ内認可 |
| can middleware | ルートレベル認可 |
| FormRequest authorize() | 入力処理と認可 |
| Blade @can | UI表示制御 |
最初は if 文で実装しても問題ありませんが、
アプリケーションが大きくなるほど 認可ロジックを整理することが重要になります。
Laravelの仕組みを使うことで、
- 認可ルールの集中管理
- コードの再利用
- 可読性の向上
といったメリットを得ることができます。