RBAC密钥权限设计实战教程 - 第2节

用户-角色-权限:三元组关系,到底是个啥?

讲RBAC,绕不开这个铁三角。说白了,就是用户不能直接拥有权限,中间必须夹着一个角色。

我早年带团队重构一个旧系统时,发现代码里全是硬编码的 if (user.id === ‘admin’) 之类的东西。结果呢?每次加新人,都得改代码。后来全推翻了,用RBAC那一套重写。嗯,世界清净了。

先看数据模型长什么样

不整那些虚的概念,我直接给你看最核心的三张表。它们的关系,就像一把钥匙开一把锁,但中间有个钥匙环——角色。

表名 核心字段 一句话解释
用户表 user_id, username 谁在操作?就是你,或者你的账号
角色表 role_id, role_name 什么身份?管理员、编辑、访客都在这
权限表 perm_id, perm_code 能干什么?比如"创建订单"、"删除用户"

光这三张不够,还得有两张关联表:用户-角色表 和 角色-权限表。这两张表决定了谁是谁,谁能干什么。

核心逻辑:到底怎么查权限?

一个用户登录后,系统怎么知道他有没有资格点那个删除按钮?流程是这样的:

  1. 拿到当前用户的 user_id
  2. 通过 用户-角色表 查出他有哪些角色
  3. 再通过 角色-权限表 查出这些角色对应的权限集合
  4. 合并去重,得到该用户最终的权限列表
  5. 在接口里去校验这个列表是否包含目标权限码

我给你看一段我常用的伪代码,清晰得很:

def check_permission(user_id, required_perm_code):
    # 1. 查用户的角色列表
    roles = get_user_roles(user_id)
    # 2. 收集所有角色拥有的权限
    perm_set = set()
    for role in roles:
        perms = get_role_permissions(role.id)
        perm_set.update(perms)
    # 3. 检查目标权限是否在集合里
    return required_perm_code in perm_set

为什么会这样设计?你想想看,如果用户直接持有权限,那是真的一团乱。每个人配一遍?公司来1000个人,配到手断。

我曾经踩过一个坑: 在角色-权限表里搞了级联删除,结果删一个角色,把其他角色关联的权限也顺手删了。教训就是:能用逻辑删除就别用物理删除,尤其是这种关联表。

权限粒度设计:粗了不行,细了也累

搞定了基本的三元组,下一个问题来了:这个权限到底要切成多细?

我习惯把权限粒度分成两层来聊:功能权限和数据权限。很多人光讲功能权限,忽略了数据权限,结果项目上线后补丁打到吐血。

功能权限:管你能不能点那个按钮

功能权限就是"能不能访问这个页面"或者"能不能执行这个操作"。比如:

  • user:create – 创建用户
  • user:delete – 删除用户
  • report:export – 导出报表

我建议你用冒号分隔的字符串作为权限码,前面是资源,后面是动作。这样一看就明白,也方便程序按前缀批量匹配。

数据权限:管你能看到哪些数据

这个才是真正的难点。同样是"查看订单"这个按钮,普通销售只能看自己的订单,销售经理能看整个团队的,财务能看到所有部门的——这不光是功能权限能解决的。

数据权限常见的几种玩法:

粒度 适用场景 实现方式
本人数据 查看自己的工单 where user_id = 当前用户
部门数据 查看本部门报表 where dept_id = 用户所属部门
全量数据 超级管理员 不加过滤条件

我在项目中惯用的做法: 功能权限放在角色里,数据权限通过一个单独的"数据范围"字段来配置,和角色解耦。这样你调整数据范围时,不用改角色配置,风险小很多。

粒度太细?小心"权限爆炸"

有的人喜欢把权限拆到每一个原子操作上,比如"保存草稿"、"提交审核"、"撤回审核"各做成一个权限。结果是角色配置累死人,权限表里几千条记录。

我的经验是:粒度做到"操作级"就够用了。像CRUD这种,一般四个权限就搞定。如果业务要求某个角色只能"编辑自己创建的内容",这个逻辑应该落到代码层面,而不是拆分权限码。

组合策略:怎么搭才不翻车?

实际落地的方案,我推荐这样的组合拳:

  • 功能权限:使用角色-权限模型,粒度到页面按钮级别
  • 数据权限:使用用户属性 + 部门树 + 自定义规则,不依赖角色
  • 特殊场景:比如临时授权,用"用户-权限"直挂表做补充,但严格控制使用

你想想看,如果所有逻辑都堆在角色里,角色本身会变成一个大泥球。拆开之后,每个模块职责清晰,改起来也安心。

我把这三层关系画成了一张图,方便你理解整体结构:

RBAC 三层权限模型 用户 User 表 角色 Role 表 权限 Permission 表 N : N N : N 👉 核心设计原则: 用户不直接持有权限,只持有角色;角色是权限的集合。 新增用户时,分配角色就行;改权限时,改角色的权限列表就行。 数据权限(独立策略层) 本人的数据 / 部门的数据 / 全部数据

总结一句: 用户-角色-权限是骨架子,粒度设计是血肉。骨架搭得正,后面的血肉才好长。否则项目越大,重构越痛。

很多新手做完前两步就觉得搞定了,回头发现数据权限没法控制,又返工。我的建议是:一开始就把功能权限和数据权限分开设计,哪怕数据权限先只做最简单的本人/全部两种,也比后加要好十倍。

嗯,这一章的内容就到这。记住,好的权限设计,最终是为了让你少加班。