Laravelではユーザーによって表示や動作を変えることができます。
そのための方法として、Gate, Policy, Middleware の3つがありますが、違いが分かりにくいですよね。
公式サイト(英語)での解説を元に、3つの方法の比較と使い方を紹介します。
Laravelで権限を設定するためのGate, Policy, Middlewareの3つ方法を比較
まずはGate, Policy, Middlewareの比較をしてみましょう。
それぞれの違いは次のとおり。
【Middleware, Gate, Policyの比較】
| 難易度 | 特徴 | |
| Gate | ★ | 特定の動作を制限 |
| Policy | ★★★ | 特定のモデルを制限 |
| Middleware | ★★ | ルート設定の段階で制限 |

難易度は、個々のコードによります。
上記は目安としてとらえてくださいね。
ひとことで用途を言うと、こうなります。
- Gateは簡単に単独で制限をかけたいときに使う
- Policyはモデルごと、リソースコントローラーごとなど、まとめて制限をかけたいときに使う
- Middlewareはルート設定の段階で制限をかけたいときに使う
ひとつのプロジェクトの中で、3つの方法を組み合わせながら使っていけます。
それぞれの方法の具体的な使い方を解説していきますね。
LaravelのGateを使った処理の方法
Gateは、入ってきた人を通すための門(ゲート)の役割を果たします。
設定方法はわりとシンプル。
今回は投稿者本人のみ、投稿のアップデートを実行できるようにするためのGateを作ってみます。
Gateの設定方法

App/Providersの中のAuthServiceProviderファイルで設定します。
ファイル上部に、つぎのふたつのモデルのuse宣言を入れておきます。
use App\Models\Post; use App\Models\User;
実際の設定はbootメソッドに入れます。
public function boot()
{
$this->registerPolicies();
Gate::define('poster', function(User $user, Post $post) {
return $user->id==$post->user_id;
});
}
posterというGateを定義。
ユーザーが投稿者と同じであれば、Gateをくぐれることにする。
Gateを使ったコントローラー例
上記のGateを使って、たとえばユーザーが投稿者本人であった場合のみ、update処理ができるよう設定します。
PostControllerのupdateメソッドに下記のように入れるだけでOK。
public function update(Request $request, Post $post)
{
if(! Gate::allows('update-post', $post)){
abort(403);
}
// アップデートの処理
}
‘update-post’ ゲートを許可されていなければ、403を返す。
ユーザー以外の人がアップデートを実行しようとすると、403画面が表示されます。

制限をビューに適用
なお作成したGate制限はビューにも適用できます。
Gateのposter制限を適用するには、ビューファイル(blade.php)の中で制限をかけたい部分を@can~@endcanで囲みます。
@can('poster',$post)
制限をかけたい部分
@endcan
Gateをくぐったユーザーにしか「制限をかけたい部分」は表示されません。
LaravelのPolicyを使った処理の方法

Policyは、特定のモデルやリソースコントローラーに対して、まとめてルールを設定します。
Gateよりも面倒ですが、ひとまとめにルールを設定したいときには便利。
PolicyでもGateで行ったと同様、今回は投稿者本人のみ、投稿のアップデートを実行するコードを作ってみます。
Policyの設定方法
Policyは新規Policy作成、Policy登録、Policyファイル編集、コントローラーに登録という4つのステップを踏んでいきます。
Gateより手順が多くなります。
①新規Policy作成
まずは次のコマンドで、新規Policyを作成します。
php artisan make:policy PostPolicy --model=Post
上記のようにモデル名をいれておくと、最初からメソッド名が入ったPolicyを作れます。
②Policyの登録
作成したPolicyは、App/Providersの中のAuthServiceProviderファイルのprotected $policiesに登録します。
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
App\Models\Post::class=>App\Policies\PostPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
}
}
③Policyファイルの編集
つぎにPolicyファイルを設定します。
App/Policiesの中のPostPolicy.phpファイルを開きます。
先頭にモデル名をuse宣言でいれておきます。
use App\Models\Post; use App\Models\User;
メソッド名は、リソースコントローラーのデフォルトルールに従って作成されています。
今回はupdateの部分に、次のようにいれておきます。
public function update(User $user, Post $post)
{
return $user->id==$post->user_id;
}
④コントローラーの編集
PostControllerのupdateメソッドには次のようにいれておきます。
public function update(Request $request, Post $post)
{
if($request->user()->cannot('update', $post)){
abort(403);
}
// アップデートの処理
}
ユーザーが’update’ ができないなら、403を返す。
もっと短く、下記でもOKです。
$this->authorize('update', $post);
ユーザー以外の人がアップデートを実行しようとすると、403画面が表示されます。

制限をビューに適用
なお作成したPolicy制限はビューにも適用できます。
Postのupdateポリシーを適用するには、ビューファイル(blade.php)の中で制限をかけたい部分を@can~@endcanで囲みます。
@can('update', $post)
制限をかけたい部分
@endcan
Policyに一致したユーザーにしか「制限をかけたい部分」は表示されません。
Policyのメリット
これだけ見ると、「Policyってめんどくさ!」って思いませんか?

正直、わたしもそう思います。
今回の例のように投稿者本人しか編集できなくするなら、Gateを作ったほうが簡単に制限をかけられます。
ただPolicyは、モデルやリソース全体に制限をかけられるのが魅力。
さきほどはPolicyファイルにupdateメソッドしか設定しませんでしたが、すべてのメソッドに制限をいれることも可能。
そのうえで、PostControllerの上部にコンストラクタを設定してしまえば、メソッドごとにPolicyについて書く必要はなくなります。
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
リソースコントローラー利用時にPolicyを適用させる方法はこちら。
LaravelのMiddlewareを使った処理の方法

最後にLaravelのミドルウェアを使った処理を紹介します。
ミドルウェアとは訪問者のリクエストに対して、ルーターとコントローラーの間にたって処理を行うメカニズム。
つまりコントローラーでの処理を行うより前に、ミドルウェアが入ってきて、動作を制御できるのです。

単独で使えば、ログイン認証のような機能に使えます。

つまりログイン機能を入れた時点で、既にMiddleware機能を使っているんですね。
GateやPolicyと組み合わせれば、ルート設定に手軽にGate,Policyのルールを適用できます。
先ほど作ったPostのupdateポリシーをルート設定に適用するには、ルート設定ファイル(web.php)に次のように入れるだけ。
Route::put('/post/{post}', 'PostController@update', function (Post $post) {
})->middleware('can:update,post')->name('post.update');
投稿者本人でない人がupdateを行おうとすると、403エラーとなります。

ミドルウェアの考え方や、いちから作る方法は他の記事で詳しく書いています。


さいごに
今回はLaravelでの制限のかけ方を解説しました。
使い分けのポイントはこちら。
今回のまとめ
- 簡単に制限をかけるならGate
- モデルごと、リソースコントローラーごとならPolicy
- ルート設定にかけるときはMiddleware
なお今回はUserとPostを使って例を紹介しました。
こういった処理を行うには、あらかじめ、UserモデルとPostモデルの間にリレーションを設定し、$postテーブルの中に$user_idを入れておく必要があります。
リレーションについては、別記事を参考にしてくださいね。





コメント