RBAC基础理论:RBAC0核心模型
聊权限模型,绕不开RBAC。说白了,RBAC就是「让角色来当中间人」。用户不直接跟权限挂钩,而是通过角色这个桥梁来获得权限。
我刚开始做SaaS那会儿,也想过直接给用户分配权限。结果呢?用户一多,权限乱成一锅粥。后来老老实实回到RBAC,世界清净了。
RBAC0:最基础的权限模型
RBAC0是RBAC家族的老大哥。其他RBAC1、RBAC2、RBAC3都是在它上面做加法。所以,搞懂RBAC0,后面的就简单了。
RBAC0定义了三个核心要素:
- 用户(User):系统的操作者,可以是人,也可以是程序
- 角色(Role):权限的集合,比如「管理员」、「编辑」、「访客」
- 权限(Permission):对某个资源的操作许可,比如「创建文章」、「删除用户」
它们的关系很简单:用户拥有角色,角色拥有权限。用户通过角色,间接获得权限。
核心公式:
用户 → 角色 → 权限
用户不直接关联权限,只关联角色。
为什么要这么设计?你想想看,如果100个用户都需要「发布文章」的权限,你是给每个用户单独配,还是创建一个「编辑」角色,然后把100个用户都丢进去?
答案很明显。角色就是权限的「打包工具」。
用户-角色-权限关系
这三者的关系,我习惯用一张表来理解:
| 实体 | 关系 | 示例 |
|---|---|---|
| 用户 ↔ 角色 | 多对多 | 一个用户可以有多个角色,一个角色也可以有多个用户 |
| 角色 ↔ 权限 | 多对多 | 一个角色可以有多个权限,一个权限也可以属于多个角色 |
| 用户 ↔ 权限 | 不直接关联 | 用户只能通过角色获得权限 |
我在项目中遇到过一个问题:一个用户同时拥有「管理员」和「普通用户」两个角色。管理员有删除权限,普通用户没有。那这个用户到底能不能删除?
答案是:能。因为RBAC0的权限是「取并集」。只要用户拥有的任意一个角色包含该权限,用户就拥有该权限。
我的建议:设计数据库时,用户-角色、角色-权限这两张关联表一定要建好。索引也别省,否则用户一多,查询性能会很难看。
会话与角色激活
嗯,这里有个容易被忽略的点:会话(Session)。
用户登录系统后,会创建一个会话。在这个会话里,用户可以选择激活哪些角色。不是所有角色都必须激活。
举个例子:
我既是「系统管理员」,又是「普通用户」。平时我只想用普通用户的功能,那就只激活「普通用户」角色。管理员权限虽然我有,但我不激活它,就不会生效。
这样做的好处很明显:
- 最小权限原则:只激活需要的角色,减少误操作风险
- 性能优化:不需要加载所有角色的权限,减少内存占用
- 安全控制:临时需要高权限时再激活,用完就关掉
我曾经踩过的坑:有个系统没做角色激活控制,用户登录后默认激活所有角色。结果一个普通用户不小心激活了管理员角色,把整个配置表删了。从那以后,我做的每个系统都强制要求用户手动选择激活角色。
会话和角色激活的关系,可以用代码简单表示:
// 用户登录后创建会话
Session session = new Session(user);
// 用户选择激活的角色
List<Role> activeRoles = session.activateRoles(
Arrays.asList("editor", "viewer")
);
// 权限检查时,只查激活的角色
boolean canPublish = activeRoles.stream()
.anyMatch(role -> role.hasPermission("publish_article"));
你看,代码逻辑其实不复杂。但少了这一步,整个权限系统就会出大问题。
小结
RBAC0的核心就三句话:
- 用户不直接拿权限,通过角色中转
- 用户和角色是多对多,角色和权限也是多对多
- 会话里只激活需要的角色,别一股脑全开
搞懂了这些,后面的RBAC1(角色分层)、RBAC2(角色约束)就好理解了。说白了,都是在RBAC0的基础上加规则。
下一章,我们聊聊角色分层和继承。嗯,那个更有意思。