核心概念解析:用户、角色、权限、会话
搞RBAC设计,绕不开这四个东西:用户、角色、权限、会话。很多人以为自己懂了,结果一落地就乱套。
我个人习惯先理清定义,再看它们怎么串起来。咱们一个一个拆。
用户(User)—— 系统里的「谁」
用户就是登录系统的那个人或服务。你想想看,一个电商平台,张三、李四、客服机器人、第三方支付网关,都是用户。
- 人:有登录凭证,比如手机号、密码或人脸。
- 服务:通过 或 JWT 代表自己。
- 设备:比如 IoT 节点、自助终端。
我的经验:永远别把用户直接绑权限。我见过一个项目,项目经理给每个用户手动勾选「可删除订单」「可查看报表」……三个月后,客户说“新来的运营没有这个权限”,排查了一整天。后来全改成角色了。
角色(Role)—— 权限的「容器」
角色就是一组权限的集合。它抽象了“某类人应该能干什么”。
比如「运营专员」角色可以:查看订单、导出报表、修改商品描述。
「运营主管」角色多一个:审核退款、分配任务。
角色可以继承。我记得一次设计:把「基础角色」作为父类,子角色只加差异项。这样维护起来清清爽爽。
| 角色名称 | 包含权限示例 | 可分配给哪些用户 |
|---|---|---|
| 访客 | 浏览商品、搜索 | 未登录用户 |
| 普通用户 | 下单、查看订单 | 注册用户 |
| 运营专员 | 管理商品、导出报表 | 公司内部运营人员 |
| 管理员 | 所有权限 | 系统维护团队 |
权限(Permission)—— 最细粒度的「操作」
权限描述“能不能对某个资源做什么”。通常拆成两部分:
- 资源:订单、商品、用户资料
- 操作:创建、读取、更新、删除(CRUD)
举个例子:order:read 表示“读取订单”,order:create 表示“创建订单”。
我建议大家按
资源:操作 的命名规范做,别自由发挥。曾经有个项目用 can_delete_order、order_delete_right 混着写,后期做审计脚本写到怀疑人生。权限本身不直接给人,而是挂到角色上。这是 RBAC 的核心思想。
会话(Session)—— 临时的「执行上下文」
会话就是用户登录后,系统为他创建的一个临时的、可撤销的「令牌」。它把用户、角色和权限绑定在一起,并且加了一个有效期。
很多人忽略会话,觉得就是。实际上会话管理做不好,权限全白搭。
- 会话包含:用户ID、激活的角色列表(一个用户可能有多个角色,会话里决定用哪个)
- 会话随时可以被终止:用户登出、管理员踢人、超时
- 权限检查都基于会话中的角色,而不是直接从用户身上拿
避坑指南:我曾经把角色直接存在客户端JWT里,以为安全。结果某次泄密攻击,攻击者伪造JWT里的角色字段,直接拿到了管理员权限。后来改成:JWT只存 sessionId,服务端用 Redis 查真实角色。不要信任客户端传来的任何权限信息。
它们的关系 —— 一张图说清楚
看这张图就容易理解了:用户登录时系统创建一个会话,会话里指定了当前激活的角色(可能有多个),角色下挂载权限。系统做鉴权时,只看会话中的角色权限集合,不会直接查用户表。
关键原则:用户不直接拥有权限,用户通过角色获得权限,角色通过会话激活。会话是运行时唯一的权限信息来源。
实际落地时需要注意的点
- 一个用户可以有多个角色:比如张三既是「运营专员」又是「测试用户」。会话时需要决定用哪个角色,或启用角色组后取并集。
- 角色不要太多:我见过一个系统建了200个角色,管理员配角色时自己都晕。一般不超过20个,够用就行。
- 权限要避免过于细碎:如果每个按钮都是一个权限,角色维护成本会爆炸。建议以“功能模块”为单位,比如“订单管理”是一个权限,里面包含增删改查。
- 会话生命周期要可控:短则15分钟,长则1天。记得给运维留一个“强制踢出所有会话”的接口,万一泄露能快速止血。
最后提醒一句:RBAC不是万能药。如果你的业务里权限判断需要根据数据状态(比如“只能删除自己创建的订单”),那纯RBAC不够,得加上ABAC(属性访问控制)。但那是后面章节的事了,咱们先把基础打牢。