Role Based Access Control
需求场景
不知道你有没有遇到过平台对“用户-访问”方面控制的需求?也就是要求平台满足:
- 非公司用户访问平台,直接拒绝
- 公司用户,但不是同部门访问平台,需要额外添加权限才能访问
- 公司同部门用户,成功访问
上面是最简单的控制的要求,一般企业的平台都是必须要满足的。就依上述需求而言,我们的实现方式可以有哪些呢?
传统解决方案
这里的“传统”,不代表“大多数“平台的使用实现方式,仅是我见过的一个企业后台项目的鉴权模式(可能其他项目也这样?🤔)。这个项目的实现非常简单和直接。

用户在经过统一认证平台登录后,访问某部门的平台,鉴权中间件去判断用户名是否存在于数据库中,存在即放行,反之拦截。
这样其实已经解决了上面的三个需求,我们只需要将有资格访问的用户名存于数据库,就能达到基本的“用户-访问”控制。可如此简单的一种实现,是否对“企业”级别的后台要求过于低呢?
在我看来,这种实现确实简单,颠覆了我以往对"企业级"这三个字的看法。但仔细想想,最基本的用户登录已由统一认证平台处理,后续只需区分是否为同部门用户及特殊用户即可。如果平台不需要更细粒度的权限控制,这种方案完全够用——简单即是最好。
注:一般公司用户都是在办公网环境下进行的,不是办公网无法访问和公司 IT 系统有关的东西!
新的解决方案
产品来了新的需求,要求平台有更细粒度的权限控制。如图:

平台需要确保用户访问的某个接口有权限!权限管理平台要求用户携带具体的 API + 请求资源,然后再进行判断。
对于这个新要求,传统的解决方式已经完全不适用,平台需要一个全新的解决方式,也就是本篇的主题:基于角色的访问控制(RBAC)。
这里不对 RBAC 做更多的解释,想要了解更多的请看【参考】。
权限管理平台
不管实现如何,RBAC 模式大致遵循以下基本原则:
- 为每个用户分配一个或多个角色
- 为各个用户角色分配权限
- 用户成为某一角色的有效成员,获得访问权限
然后分为三个模块:角色、操作组、资源
- 角色:决定用户能够操作什么接口,同时还决定用户能拥有什么资源
- 操作组:一堆操作的集合,可以简单理解为后端的接口
- 资源:万物皆资源,游戏 id,应用,配置,函数等等
基于此设计的权限模型:

整体的鉴权流程:

流程说明:
- 请求入口:接收带有用户id、请求的 api 以及资源
- 获取用户绑定的角色:根据用户 id 查询其绑定的角色
- 获取角色绑定的操作组:获取该角色可以访问的接口组
- 判断api是否在操作组内:
- 否 → 拦截
- 是 → 继续判断
- 判断操作组是否依赖资源:
- 否 → 放过
- 是 → 获取用户+角色绑定的资源
- 判断请求资源是否在绑定列表中:
- 是 → 放过
- 否 → 拦截
可以看到 RBAC 模式可以很好解决新的需求,达到更细粒度的权限控制和管理,只是会增加一定的开发/维护成本。
RBAC 也并非完美的权限控制模式,只是非常适合当下的场景:
- 组织结构清晰,角色定义明确
- 权限模型相对稳定
- 需要合规审计的系统
此外,在实际应用中,有些用户和接口是不需要鉴权的,我们可以单独在配置里(数据库)维护一个白名单。
注:如果权限需求高度动态化、需要基于多维属性的复杂授权、资源级别的细粒度控制要求高,可能使用 ABAC(基于属性的访问控制) 模式会更好。
降级
在企业环境中,权限管理平台通常作为公共服务单独部署,供多个业务平台调用。这种架构下,权限服务一旦故障,将影响所有依赖它的业务系统。因此,我们需要设计合理的降级策略,确保权限服务不可用时,业务系统仍能在可控风险内继续运行。
这里的降级策略因平台重要性、ToB or ToC、使用人员数量、数据一致性等考虑其最佳实现方式。
在这里我给出一个基于本地缓存实现的降级策略:

这里面有几个要点:
- 构建缓存 KEY:user_id + api + resource,设置缓存 TTL
- 请求三次避免网络抖动问题
- 重试间隔(
100ms)以及请求超时间隔(1s),参考平台情况 - 触发降级的条件必须是权限管理平台不可用(如超时、网络错误),而非业务逻辑返回的"无权限"或其他错误
- 宁可误拒用户,不可误放已取消权限的用户
方案对比
| 维度 | 传统方案(白名单) | RBAC 方案 |
|---|---|---|
| 实现复杂度 | 低 | 中等 |
| 权限粒度 | 用户级别 | 接口 + 资源级别 |
| 维护成本 | 低 | 中等 |
| 扩展性 | 差 | 好 |
| 适用场景 | 简单访问控制 | 细粒度权限管理 |
总结
权限系统的设计,本质上是在安全性、可用性、复杂度之间寻找平衡点。从白名单到 RBAC,再到 ABAC,每一步演进都是为了应对更复杂的业务场景,但切记:够用就好,过度设计是另一种浪费。