Dcat Admin 使用 Laravel 的拦截器 Gate 和策略 Policy,能否对除 App\Models\User 模型以外的其它认证模型进行授权呢?
运行环境
- Valet 集成环境
当前使用的 Laravel 版本?
- Laravel Framework 9.33.0
- Dcat Admin version 2.2.2-beta
当前使用的 php/php-fpm 版本?
- PHP 版本:PHP 8.1.20 (cli) (built: Jun 22 2023 06:14:35) (NTS)
- php-fpm 版本:/usr/local/etc/php/8.1/php-fpm.conf
当前系统
- MacOs
问题描述?
- 最近使用
Dcat Admin
后台框架搭建了一个项目:后台有通用的
RBAC
管理模块,包括管理员、角色、权限以及角色和权限分配等相关内容。使用还比较很方便,但是最近漏扫发现了一个问题: 普通管理员,通过修改路由链接参数值,能够进入超级管理员信息的xxx/admin/auth/users/{参数id}/edit
编辑页面,然后进行密码修改获得超管账号
- 我就联想到
Laravel
中的Gate
和Policy
可以帮助我实现这个功能:它很安全,即使用户已经通过了「身份验证(authentication)」, 用户也可能无权对应用程序中重要的模型或数据库记录进行删除或更改。简单、条理化的系统性,是 Laravel 对授权管理的特性。
首先我使用 Policy
:
创建
policy
类php artisan make:policy AdminPolicy --model=Dcat\Admin\Admin
AdminPolicy
类内容<?php namespace App\Policies; use App\Models\Admin\AdminUser; use Dcat\Admin\Models\Administrator; use Dcat\Admin\Models\Role; use Illuminate\Auth\Access\HandlesAuthorization; use Illuminate\Auth\Access\Response; class AdminPolicy { use HandlesAuthorization; /** * Determine whether the user can view any models. * * @param Administrator $user * @return Response|bool */ public function viewAny(Administrator $user): Response|bool { return $user->isAdministrator(); } /** * Determine whether the user can view the model. * * @param Administrator $user * @param AdminUser $adminUser * @return Response|bool */ public function view(Administrator $user, AdminUser $adminUser): Response|bool { return intval($user->getAttribute('id')) === intval($adminUser->getAttribute('id')); } /** * Determine whether the user can create models. * * @param Administrator $user * @return Response|bool */ public function create(Administrator $user): Response|bool { return $user->isRole(Role::ADMINISTRATOR) || $user->isRole('manager'); } /** * Determine whether the user can update the model. * * @param Administrator $user * @param AdminUser $adminUser * @return Response|bool */ public function update(Administrator $user, AdminUser $adminUser): Response|bool { return intval($user->getAttribute('id')) === intval($adminUser->getAttribute('id')); } /** * Determine whether the user can delete the model. * * @param Administrator $user * @param AdminUser $adminUser * @return Response|bool */ public function delete(Administrator $user, AdminUser $adminUser): Response|bool { return intval($user->getAttribute('id')) === intval($adminUser->getAttribute('id')); } /** * Determine whether the user can restore the model. * * @param Administrator $user * @param AdminUser $adminUser * @return Response|bool */ public function restore(Administrator $user, AdminUser $adminUser): Response|bool { return intval($user->getAttribute('id')) === intval($adminUser->getAttribute('id')); } /** * Determine whether the user can permanently delete the model. * * @param Administrator $user * @param AdminUser $adminUser * @return Response|bool */ public function forceDelete(Administrator $user, AdminUser $adminUser): Response|bool { return intval($user->getAttribute('id')) === intval($adminUser->getAttribute('id')); } }
在
AuthServiceProvider
提供者中注册polic
类protected $policies = [ AdminUser::class => AdminPolicy::class, ];
在控制器中使用
public function edit($id, Content $content): Content { $adminUser = AdminUserModel::query()->find($id); $response = Gate::inspect('view', $adminUser); // 第一种:打印结果第一个为 false ,第二个为 null // 无论是自己的信息,还是不是自己的信息,都返回 false dd($response->allowed(), $response->message()); // 第二种:直接返回 403 权限验证失败页面 Gate::authorize('view', AdminUserModel::query()->find($id)); }
然后我使用 Gate
:
AuthServiceProvider
中boot
方法注册方法Gate::define('admin-view', function (Administrator $user, AdminUser $adminUser) { return $user->getAttribute('id') === $adminUser->getAttribute('id'); });
控制器中验证
public function edit($id, Content $content): Content { $adminUser = AdminUserModel::query()->find($id); $status = Gate::allows('admin-view', $adminUser); // 打印结果一直为 false dd($status); if (! $status) { abort(403); } }
您期望得到的结果?
Policy
和 Gate
能够验证,除 App\Models\User
以外的用户认证模型:比如说后台 App\Models\Admin\AdminUser
模型
您实际得到的结果?
最终验证不了, Policy
和 Gate
方法默认的第一个参数,就是 认证用户
,这个认证用户没搞明白是哪个模型的认证用户,所以得不出结果。
推荐文章: