当記事はUdemyの講座、Vue 3 and Laravel: A Practical Guide with Dockerを進めるにあたり、理解を深めるために記された備忘録です。
今回はGateを用いてコントローラの各メソッドに対するアクセス権限を限定します……が、Gateに関しては元講座におけるインストラクターの方の説明が相当巻いていたため、何なら**黒魔術としてGateを運用しよう!**ぐらいのスタンスで当記事は執筆される運びとなりました。
まあ私的な備忘録なんてそんなものと言えばそうなのですが……。
リレーションについて
前提として、元講座は以下のようなリレーションを行っている。
- ユーザー(User)はそれぞれ、「管理者(admin)」「編集者(editor)」「閲覧者(viewer)」のいずれかの役割(Role)を持つ。これはRoleとUsersのOne to Manyリレーションシップで表現されている。
- 「管理者」「編集者」「閲覧者」の役割(Role)はそれぞれに「権限」(Permission)を持つ。これはRolesとPermissionsのMany to Manyリレーションシップで表現されている。
- 「権限」は「view_users」「edit_users」「view_roles」「edit_roles」「view_products」「edit_products」「view_orders」「edit_orders」の8つである。一読すればわかる通り、これらはUsers、Roles、Products、Ordersに関する閲覧(index、show)と編集(create、update、destroy)の権限をそれぞれ表している。
モデルについて
上記のリレーションはややこしいが要点としては簡単で、Userが持つRoleが持つPermissionsに、当該モデルに関する権限が書いてあると考えればいい。
ここに一介の閲覧者(viewer)であるJohn Smith氏がいたとしよう。彼の持つ権限の一覧は以下のようにすれば列挙できる。
return $johnSmith->role->permissions->pluck("name");
[
"view_users",
"view_roles",
"view_products",
"view_orders"
]
ここでUserモデルに少し手を加える。
あるユーザーが特定のpermissionを有しているかを確かめるhasAccess()
メソッドを追加するのだ。
public function hasAccess($access){
return $this->role->permissions->
pluck("name")->contains($access);
}
$johnSmith->hasAccess("edit_roles");
//上記はfalsyとなる
$johnSmith->hasAccess("view_roles");
//上記はtruthyとなる
コントローラについて
Gateを用いて各種メソッドへのアクセスを制限するには、以下の一文をそれぞれ追加するだけでいい。
public function destroy($id){
\Gate::authorize("edit","roles");
//ここを追加する
Role::destroy($id);
return response(null,Response::HTTP_NO_CONTENT);
}
アクセスを与えるPermission(この場合はedit_roles
)のアンダーバーより前の部分を第一引数に、それより後を第二引数に指定する。
AppServiceProvider
続いてApp\Providers\AppServiceProvider
のboot()
関数内で、Gateの挙動を指定する。
ここのコードはかなり黒魔術っぽいが、機能は何となく理解できる。
以下インラインに示す。
\Gate::define("view",
//Gate::authorize()の第一引数ごとに挙動を指定できる
function(User $user,$model){
//この関数の第一引数は各Gateにアクセスしたユーザであり、
//第二引数はGate::authorize()の第二引数である。
return $user->hasAccess("view_{$model}") ||
$user->hasAccess("edit_{$model}");
});
//上記でモデルに追加したhasAccessメソッドの出番である。
//trueが返ればGateを通過できる。falseだと通過できない。
//以下、Gate::authorizeの第一引数がeditだった際のの挙動も指定する
\Gate::define("edit",
function(User $user,$model){
return $user->hasAccess("edit_{$model}");
});
これでGateを用いて各メソッドへのアクセスを権限ごとに制限することができた。