Laravel中如何在User模型政策中获取待查看的模型实例?
Laravel政策中获取待操作模型实例的问题解决
问题
我想为应用中的User模型创建政策,已在包的服务提供者中通过Gate门面完成政策注册:
Gate::policy(\MyVendor\Package\Models\User::class, \MyVendor\Package\Policies\UserPolicy::class);
在UserController中遵循资源控制器命名规范设置了政策:
public function __construct() { $this->authorizeResource(User::class, 'user'); }
路由配置如下:
Route::get('{user}/view', 'show')->middleware(['permission:viewAny users'])->name('admin.users.show');
对应的展示用户方法:
public function show(User $user) : View { return view('my-package::admin.users.view', [ 'user' => $user // 待展示的用户 ]); }
政策方法中的第一个User $user代表当前认证用户,权限由spatie/laravel-permission包配置的角色提供,原政策的view方法如下:
public function view(User $user) : bool { return $user->can('viewAny users'); }
我希望将待查看的用户模型传入政策,比如判断当前认证用户是否就是待查看的用户,若是则返回true。我尝试修改控制器中的参数名:
public function __construct() { $this->authorizeResource(User::class, 'userModel'); }
并在政策中调整:
public function view(User $user, User $userModel) : bool { if($user->id === $userModel->id) { return true; } return $user->can('viewAny users'); }
但修改后所有请求都被禁止,此前是正常工作的。请问如何在政策方法中访问待查看的模型实例?
解决方案
问题根源
修改authorizeResource的参数名后,路由中的参数名{user}和控制器构造方法里指定的userModel不匹配,导致Laravel无法正确将路由模型绑定的实例传入政策方法,政策获取不到待查看的用户实例,最终权限验证失败。
正确实现步骤
- 保持控制器构造方法的原有配置,参数名与路由中的
{user}一致:
public function __construct() { $this->authorizeResource(User::class, 'user'); }
- 在政策的
view方法中添加第二个参数,接收待查看的目标用户实例(参数名可自定义,比如targetUser):
public function view(User $currentUser, User $targetUser) : bool { // 当前用户查看自己直接通过权限验证 if($currentUser->id === $targetUser->id) { return true; } // 否则检查是否拥有全局查看用户的权限 return $currentUser->can('viewAny users'); }
关键注意事项
authorizeResource的第二个参数必须和路由定义中的参数名({user})完全匹配,Laravel才能自动完成路由模型绑定,并将实例注入到政策方法的第二个参数中。- 政策方法的参数顺序固定:第一个参数是当前认证用户,第二个参数是待操作的目标模型实例。
- 路由中配置的
permission:viewAny users中间件会优先于政策验证执行,如果用户没有该权限会直接被拦截。如果想让“自己查看自己”的逻辑绕过该中间件,建议移除路由上的该中间件,完全由政策统一处理权限判断逻辑。
内容的提问来源于stack exchange,提问作者Swiftor
相关产品推荐
相关产品推荐

