You need to enable JavaScript to run this app. 如何在Laravel中基于Eloquent实现分角色用户授权
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中基于Eloquent实现分角色用户授权

核心问题解答

该场景完全不需要强制使用Laravel的Gate授权机制。
Gate本质是面向全局场景的授权规则注册入口(比如判断用户能不能访问系统设置页这类不绑定具体模型的权限),本场景是围绕Member模型的省份维度做数据权限隔离,更适合用全局查询作用域+请求参数校验的轻量方案实现,代码复用性更高、漏写权限判断的风险更低。

完整实现流程

前置步骤:补全模型关联关系

先把各模型的关联逻辑补全,为后续权限判断提供基础:

  • User模型添加两个关联方法:
    • role():定义belongsTo关联,对应roles表的外键role_id
    • operatorAccess():定义hasMany关联,对应OperatorAccess模型的外键user_id
  • 在User模型中封装公共权限判断方法,统一获取当前用户可操作的省份集合,可加缓存减少重复查询:
    public function getAuthorizedProvincesAttribute()
    {
        // admin角色无省份限制,返回特殊标记
        if ($this->role->role === 'admin') {
            return collect(['*']);
        }
        // operator角色返回自身绑定的所有省份
        return $this->operatorAccess->pluck('province');
    }
    

第一步:查询层权限隔离(解决列表查看越权问题)

在Member模型中定义全局查询作用域,从数据库查询层面直接过滤当前用户无权访问的省份数据,避免每个控制器单独写where条件漏判:

// Member模型内定义作用域
public function scopeAccessibleByUser($query, $user)
{
    // admin不过滤任何数据
    if ($user->authorized_provinces->contains('*')) {
        return $query;
    }
    // operator仅匹配自身有权限的省份
    return $query->whereIn('province', $user->authorized_provinces);
}

所有查询成员数据的接口,直接链式调用该作用域即可:
Member::accessibleByUser(auth()->user())->paginate()

第二步:写入操作权限校验(解决新增、更新、删除越权问题)

  • 新增/更新操作:在对应的FormRequest校验类中,校验用户提交的province参数是否在自身权限范围内:
    // StoreMemberRequest / UpdateMemberRequest 类内的校验逻辑
    public function rules()
    {
        $user = auth()->user();
        // admin无限制
        if ($user->authorized_provinces->contains('*')) {
            return [];
        }
        return [
            'province' => [
                'required',
                function ($attribute, $value, $fail) use ($user) {
                    if (!$user->authorized_provinces->contains($value)) {
                        $fail('你没有权限操作该省份的成员数据');
                    }
                }
            ]
        ];
    }
    
  • 删除操作:删除前先通过前面定义的作用域查询对应成员记录,如果查询不到则直接返回403,避免用户通过修改ID删除其他省份的成员:
    // 控制器内删除逻辑示例
    public function destroy(Member $member)
    {
        $user = auth()->user();
        // 如果当前用户没有权限操作这条记录(对应省份不匹配)
        if (!Member::accessibleByUser($user)->where('id', $member->id)->exists()) {
            abort(403, '无权限操作该数据');
        }
        $member->delete();
        return back();
    }
    

可选的优化方向

如果后续业务扩展出更多权限规则(比如新增角色、开放字段级编辑权限),可以把散写的省份判断逻辑收敛到MemberPolicy类中,配合Laravel控制器的authorize()方法统一调用,全程不需要定义全局的Gate规则,维护成本更低。

内容的提问来源于stack exchange,提问作者Ismynr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.28 00:15:03