如何为Laravel嵌套资源控制器的两个show方法创建独立Policy?
实现步骤
1. 生成两个独立的Policy
执行Artisan命令生成对应的策略类:
php artisan make:policy CompanyAddressPolicy php artisan make:policy UserAddressPolicy
2. 实现策略类逻辑
CompanyAddressPolicy(公司地址权限)
路径:app/Policies/CompanyAddressPolicy.php
<?php namespace App\Policies; use App\Models\User; use App\Models\Company; use App\Models\Address; class CompanyAddressPolicy { /** * 判断用户是否可查看公司地址 */ public function view(User $currentUser, Company $company, Address $address): bool { // 安全校验:确保当前地址属于指定公司,避免参数篡改越权 if ($address->addressable_id !== $company->id || $address->addressable_type !== Company::class) { return false; } // 权限判断:A、B角色可查看,C无权限 // 此处可替换为你实际的权限判断逻辑,如权限标签、角色表判断等 return in_array($currentUser->role, ['A', 'B']); } }
UserAddressPolicy(用户地址权限)
路径:app/Policies/UserAddressPolicy.php
<?php namespace App\Policies; use App\Models\User; use App\Models\Address; class UserAddressPolicy { /** * 判断用户是否可查看用户地址 */ public function view(User $currentUser, User $targetUser, Address $address): bool { // 安全校验:确保当前地址属于指定用户,避免参数篡改越权 if ($address->addressable_id !== $targetUser->id || $address->addressable_type !== User::class) { return false; } // 权限判断:仅A角色可查看 return $currentUser->role === 'A'; } }
3. 控制器中调用授权
嵌套资源场景下,不需要把策略绑定到Address模型(避免同模型多策略冲突),直接在对应方法中手动指定策略类调用授权即可:
CompanyAddressController 调整
class CompanyAddressController { public function show(Request $request, Company $company, Address $address) { // 传入策略类 + 路由参数(参数顺序和策略方法的参数顺序保持一致) $this->authorize('view', [CompanyAddressPolicy::class, $company, $address]); // 原有业务逻辑 } }
UserAddressController 调整
class UserAddressController { public function show(Request $request, User $user, Address $address) { $this->authorize('view', [UserAddressPolicy::class, $user, $address]); // 原有业务逻辑 } }
可选:全控制器资源自动授权方案
如果需要给控制器所有资源方法做授权,可以通过创建代理模型的方式实现authorizeResource自动绑定:
- 给两类地址创建继承自
Address的空代理模型:
// app/Models/CompanyAddress.php class CompanyAddress extends Address { // 无需额外逻辑,仅做策略绑定标识 } // app/Models/UserAddress.php class UserAddress extends Address { }
- 在
app/Providers/AuthServiceProvider.php的$policies数组中注册绑定:
protected $policies = [ // 其他已有绑定 \App\Models\CompanyAddress::class => \App\Policies\CompanyAddressPolicy::class, \App\Models\UserAddress::class => \App\Policies\UserAddressPolicy::class, ];
- 控制器中开启自动授权,参数替换为对应代理模型:
class CompanyAddressController { public function __construct() { // 第二个参数对应路由中的地址参数名address $this->authorizeResource(CompanyAddress::class, 'address'); } public function show(Request $request, Company $company, CompanyAddress $address) { // 无需手动调用authorize,自动完成授权校验 } }
内容的提问来源于stack exchange,提问作者jhine
相关产品推荐
相关产品推荐

