RBAC 困局

在多年工作之中对于后台管理的权限开发比较常见的是采用 RBAC 模型, 主要提供以下便利

  • 有效分配权限
  • 保护敏感数据
  • 用户分组管理

比如常见的工会组织: 创建 XX工会 分组角色并在后台创建批次账号绑定该角色, 最后对该角色分配允许访问的入口和功能

毕竟这个后台角色已经经受时间的考验, 一般不会出现比较大的问题, 但是在日新月异的需求之中也开始出现问题

  • 角色混乱: 如果需要制定角色只能看数据A/{不}允许编辑数据B/{不}允许导出数据, 就需要针对创建多个角色分配账户

  • 权限混乱: 传统 RBAC 只能处理允许访问指定菜单/功能, 没办法针对可视数据(工会成员只允许查看自己, 会长看所有成员数据)

  • 影响广泛: 涉及到某个角色组需要变动功能, 为了保证不影响其他相关账号, 需要手动创建分组在规划一遍权限并管理账号

内部业务固定并且用户比较少量的时候就没问题, 但是用户量级上来之后就会出现相关功能实现及其复杂且不可控

这里说下最典型的场景, 以游戏发行说明大概流程:

  • 游戏发行最简单角色有 最高管理员/运营管理员(游戏研发)/渠道管理员(推广工会)

  • 运营管理员相对比较好处理, 只能看到自己绑定的对应应用和注册/支付玩家

  • 渠道管理员就比较复杂, 涉及到应用渠道出包等, 普通成员只看到自己关联数据, 最高组织者可以看成员数据

  • 统计数据需要针对指定角色来筛选出不同汇总数据, 有时候甚至需要单独处理某些批次的角色

如果相同接口堆叠这些业务的话, 那么内部的代码判断会特别复杂:

  • 最高账户可以看到全部汇总统计, 运营账户只能看到旗下应用汇总, 渠道账户分为自身汇总或者全部成员汇总

  • 所有内部接口都要做单独请求授权判断, 避免被木马渗透之后直接请求攻击相关接口

  • 细分角色越多后期接手的后台运营人员越难理清, 就要出文档让他们去了解整体关系

我曾经维护过这部分项目, 整体每个接口开头都要做大量渠道判断识别, 而且有时候部分业务需要针对某些渠道做单独处理

那部分堆叠起来的权限代码维护起来特别难受, 并且导致运营人员每次都要求指定某个单独渠道要求开放某些功能

可以说整个项目都是缝缝补补的代码补丁, 越改动后面维护起来越危险

所以在后续这种业务上面, 我习惯性采用将角色当作 资源 的简洁模块划分

角色资源

什么是角色资源? 实际上就是沿用 REST-API 业务术语, 将 URL 请求服务路径作为资源来消费, 比如下面

1
2
3
4
5
6
7
8
9
10
https://dashboard.example.com/{manager}         -> 指向最高管理员角色
https://dashboard.example.com/{manager}/app -> 获取最高管理员应用列表页面

https://dashboard.example.com/{operator} -> 指向运营管理员角色
https://dashboard.example.com/{operator}/app -> 获取运营管理员应用列表页面

https://dashboard.example.com/{channel} -> 指向渠道管理员角色
https://dashboard.example.com/{channel}/app -> 获取渠道管理员应用列表页面

对应分配的角色访问对应 '{角色标识}/{业务入口}' 地址, 不能访问其他的角色入口

这套架构的主要核心规则如下

  • 一个角色 = 一个独立的 URL 命名空间(前缀)

  • 一个命名空间 = 一套独立业务逻辑

  • 权限 = 能否访问该命名空间

  • 数据隔离 = 命名空间内部自动处理

这样架构的后台角色处理带有大量的好处

  • 对于项目开发人员, 不需要在同一接口来编写大量 if-else 判断权限代码, 直接抽象 Service 层做数据提取并按权限组合

  • 对于运营管理人员, 只是创建对应资源下的账户并且针对账户分配高级功能权限即可(是否支持导出数据和创建子账户)

  • 对于渠道推广人员, 只需要在创建用户的时候配置是否允许创建子渠道账户或者允许看到全部成员数据即可

  • 对于后续新人接手, 只需要了解对应角色路径即可, 可以直接让他上手编写测试路径模块而不会影响到整体

当然内部可能会出现重复代码, 但是这些重复代码都是为了后续运营人员提出某些特定渠道功能预留的, 这些冗余都不算问题

可扩展、可隔离、可安全的需求远比代码复用率重要, 少量重复和冗余是可以被接受的

传统的 RBAC 架构试图用一套逻辑适配所有角色, 但是最终必然走向补丁堆砌、权限混乱、维护困难的问题, 所以需要根据项目需求来适配架构