LaravelでGate・Policyを使って表示や操作の制限をする方法

LaravelでGate・Policyを使って表示や操作の制限をする方法

849 回閲覧されました

みなさんこんにちは、jonioです。

今回はLaravelでGate・Policyを使ってページや動作の制限をする方法を学んだのでアウトプットの記事になります。

調べた内容なので間違っていたら申し訳ありません。

随時内容の追加や変更をします。

 

認可とは

GateやPolicyについて調べるとリファレンスなどネットの情報に「認可」という言葉が出てきます。

これは「その人に権限があるか」という意味になります。

 

Gate

Gateは以下の場合に使うみたいです。

  • 特定のユーザーに特定の動作の認可をしたい
  • 特定のユーザーに特定の内容を見せたい

具体的にコードを見て行きます。

 

Gateの設定

前提としてログインユーザーのモデルをUserとして投稿内容のモデルをPostとします。

またリレーションの設定をしてpostsテーブルにuser_idカラムがあるとします。

Postモデルに↓の記述があるとします。

それではGateの設定です。

「Laravelのプロジェクト > app > Providers > AuthServiceProvider.php」に記述をしますが最初の状態は↓です。

それを↓にします。

37行目でUserモデルとPostモデルを使うので10行目・11行目の設定があります。

31行目のbootメソッドの中にGateの設定(37行目〜42行目)をします。

Gateの設定をする為の記述は↓です。

Gateの名称は自由に決める事ができて今回は「poster」とします。

AuthServicrProvider.phpの38行目〜41行目の意味は「ログインユーザーのidと投稿者のidが同じならtrueを返してそうじゃない場合はfalseを返す」という意味です。

それではGateの設定をアクションとビューに使ってみます。

 

Gateをアクションに利用

ログインユーザーが投稿している場合のみ投稿内容の更新ができるとします。

コントローラーを作成してupdateアクションに↓の記述をします。

3行目の「poster」はAuthServiceProvider.phpで設定したGateの名称です。

3行目〜5行目のelseの前までの意味は「Gateの設定に当てはまってない場合は403を表示する」です。

6行目に投稿内容の更新をする為の記述をします。

次はGateをビューに利用する場合です。

 

Gateをビューに利用

AuthServiceProvider.phpでGateの設定をした時に名称を「poster」にしましたがこれを使います。

適当にビューを作成してそれにGateの設定を適用します。

普通ならありえないですがGateの設定に当てはまった場合に投稿者が投稿した内容を表示するとします。

コードを↓にします。

「@can(‘ゲート名’)@endcan」の「」にGateの設定に当てはまった場合の内容を書きます。

 

Gateをビューに使う時の欠点

Gateを設定した部分にどこかのページに飛ぶリンクがあったとします。

リンク先はGateの設定に当てはまってない場合は表示されませんが直接URLを入力すればリンク先へ移動する事ができます。

これを防ぐ為にミドルウェアを使います。

ミドルウェアが何か分からない方は↓を読んで下さい。

ルーティング(web.php)に設定をしますが↓にします。

これをふまえてコードを↓にします。

これで「ドメイン/profile/index」にアクセスすると403エラーになります。

次はPolicyです。

 

Policy

Policyは以下の場合に使うみたいです。

  • 特定のモデルやリソースコントローラーに対してまとめて認可したい

具体的にコードを見て行きます。

Policyの場合もGateの場合と同様に投稿者の場合に投稿内容を更新できるとします。

 

新規Policyの作成

↓のコマンドで新規Policyの作成をします。

「–model=モデル名」を付けると最初からリソースコントローラーに対応したメソッドがPolicyに作成されます。

今回のコマンドは↓とします。

Policyの名前を「PostPolicy」としていますが「モデル名Policy」とするとどのモデルに対してPolicyを設定しているかが分かりやすくなると思います。

 

Policyの登録

作成したPolicyは「Laravelのプロジェクト > app > Providers > AuthServiceProvider.php」に登録します。

AuthServiceProvider.phpは最初の状態は↓です。

16行目を↓にします。

App\Models\Post::class=>App\Policies\PostPolicy::class,」に変更しましたが「Post」はPolicyを適用したいモデル名でPostPolicyは先程作成したPolicy名です。

 

Policyファイルの編集

作成したPolicyファイルは「Laravelのプロジェクト > app > Policies > PostPolicy.php」にありますがこれを編集をします。

最初の状態は↓です。

これを↓にします。

updateメソッドを修正していますがリソースコントローラー(PostController.phpとします)のアクションとPolicyのメソッドを対応させないといけません。

対応は以下となります。

左側がリソースコントローラーのアクション名で右側がPolicyのメソッドです。

  • index : viewAny
  • show : view
  • create : create
  • store : create
  • edit : update
  • update : update
  • destroy : delete

今回は投稿内容の更新をしたいので↑の一覧の下から2つ目になります。

だからPostPolicy.phpの61行目を編集しています。

 

コントローラーのアクションの編集

Policyのupdateメソッドに対応するのがPostController.phpのupdateアクションに対応するのでupdateアクションに記述します。

3行目のauthorizeメソッドでPolicyを適用できます。

「$this->authorize(‘update‘, $post);」の「update」はPostPolicy.phpのupdateメソッドで「$post」は1行目の「Post $post」の$postです。

これで投稿者以外が投稿内容の編集をしようとすると403エラーになります。

 

Policyをビューに適用

Gateの時と同様にPolicyでもビューに制限ができます。

適当にビューを作成してそれにPolicyの設定を適用します。

普通ならありえないですがPolicyの設定に当てはまった場合に投稿者が投稿した内容を表示するとします。

「@can(‘Policyのメソッド名’)@endcan」の「」にPolicyに当てはまった場合の内容を書きます。

 

Policyのメリット

コントローラーのアクションに対してPolicyを適用しましたが1つのアクションだけ制限するならGateの方が簡単にできるのでわざわざPolicyを使う必要はありません。

でもPolicyはリソースコントローラーの全てのアクションに対して制限をかける事ができるのでその点が便利です。

その場合はPostController.phpにコンストラクタを追加します。

3行目の「Post」はモデル名で「post」はリファレンスに↓の記載がありました。

「2番目の引数としてモデルのIDを含むルート/リクエストパラメーターの名前を受け入れます。」はターミナルで「php artisan route:list」をした時の↓の赤枠の事だと思います。

 

注意点

今のPostPolicy.phpは↓です。

67行目のdeleteメソッドは誰でも使えるとしてPolicyの設定をしなかったら403エラーになります。

Policyの設定をしない場合は↓にします。

これは他のメソッドにPolicyの設定をしない場合も同じです。