B2B SaaS 的权限设计不是“管理员能看全部、普通成员只能查看”这么简单。真实系统还要回答:用户属于哪个租户、能对什么资源做什么、能看到哪些数据和字段、权限从哪里继承、何时失效,以及每次高风险操作如何审计。
本文从产品方案和验收角度设计权限模型,不替代安全架构评审。身份认证回答“你是谁”,授权回答“你现在是否能执行这个动作”;前端隐藏按钮也不等于服务端完成授权。
在画角色和权限前,先用B端客户访谈模板与需求证据矩阵确认购买者、管理员、终端用户和审计人员的真实职责,避免把组织头衔直接等同于系统角色。
一、先写授权句子
把权限统一写成:
主体 Subject 能否在租户 Tenant 内,基于上下文 Context,对资源 Resource 执行动作 Action?
例如:
华东区销售主管能否在 A 公司租户内,导出自己团队负责客户的脱敏列表?
一句话中至少包含:
- 主体:用户、用户组、服务账号或代表用户执行的 Agent;
- 租户:客户组织及其工作空间;
- 资源:客户、合同、报表、账单或配置;
- 动作:查看、创建、编辑、删除、导出、审批或授权;
- 范围:本人、团队、部门、区域、指定对象或全部;
- 上下文:时间、设备、网络、数据状态和审批状态。
NIST 将 RBAC 描述为通过角色集合管理用户获得的资源操作权限,其核心关系包括用户—角色和角色—权限,并可加入角色层级与职责分离约束。可参考 NIST RBAC FAQ。
二、租户隔离必须先于角色
在多租户系统里,权限判断的第一层是租户边界。即使两个租户都有“管理员”,A 租户管理员也不能访问 B 租户资源。
基础规则:
- 所有租户资源都有不可为空的 tenant_id;
- 当前会话必须明确活动租户;
- 服务端根据可信身份解析租户,不接受客户端自行声明;
- 查询和写入同时校验租户;
- 缓存、搜索索引、文件和异步任务也携带租户边界;
- 平台运维访问与客户管理员权限分开,并单独审计。
AWS 的多租户 SaaS 授权指导将策略决策点与策略执行点作为一致授权模型的一部分,提供 RBAC、ABAC 等设计方式,可作为架构沟通参考:多租户 SaaS 授权设计模型。
三、把“菜单权限”拆成四层
1. 功能与页面
是否能进入客户管理、合同、账单或组织设置模块。这一层主要影响导航和产品可发现性,不应成为唯一安全校验。
2. 动作
在资源上执行原子动作,例如:
customer.read customer.create customer.update customer.delete customer.export customer.assign
不要用一个模糊的 customer.manage 覆盖所有高风险动作,否则无法区分编辑、删除、导出和转移归属。
3. 数据范围
即使都拥有 customer.read,不同角色可见范围也不同:
- 仅本人负责;
- 本人及下属;
- 所属团队;
- 指定部门或区域;
- 通过共享关系获得;
- 当前租户全部。
4. 字段与敏感操作
手机号、身份证号、成本、薪资或合同金额可能需要脱敏、独立授权或二次确认。字段可见、字段可编辑和整表导出应分别定义。
四、从最小 RBAC 开始
先用角色聚合稳定的工作职责:
| 角色 | 客户查看 | 客户编辑 | 导出 | 账单 | 成员授权 |
|---|---|---|---|---|---|
| 销售 | 本人 | 本人 | 否 | 否 | 否 |
| 销售主管 | 团队 | 团队 | 需审批 | 否 | 否 |
| 财务 | 合同关联客户 | 否 | 财务字段 | 查看 | 否 |
| 租户管理员 | 全租户 | 全租户 | 是 | 管理 | 是 |
内置角色降低初始化成本,自定义角色满足客户差异。不要直接按具体员工建大量一次性角色,否则角色会迅速失控。
何时需要属性或关系
RBAC 无法简洁表达以下规则时,再补充:
- 仅能在合同“草稿”状态编辑;
- 只有数据所属区域与用户区域一致时可查看;
- 临时项目成员在到期日前可访问;
- 文档所有者可邀请指定协作者;
- 高金额退款需要不同于申请人的审批者。
这些规则分别涉及资源属性、环境属性、对象关系和职责分离。复杂度增加后,需要可解释的权限预览和自动测试,不能把规则散落在页面代码里。
五、默认拒绝与最小权限
OWASP 的授权指南建议最小权限、默认拒绝、每个请求校验权限、记录适当日志并建立自动测试。详见 Authorization Cheat Sheet。
落实到产品规则:
- 新功能和新资源没有明确规则时默认不可访问;
- 用户只获得完成职责所需的最小权限;
- UI、API、导出、批量任务和静态文件执行一致校验;
- 对象 ID 可猜到也不能越权读取;
- 高风险操作不因“用户已经登录”而跳过授权;
- 权限失败返回安全结果,不泄露资源是否存在。
六、管理员配置流程
权限后台至少支持:
- 查看内置和自定义角色;
- 创建角色并选择原子权限;
- 配置数据与字段范围;
- 给用户或用户组分配角色;
- 预览某用户的最终有效权限;
- 显示权限来源、继承和冲突;
- 对高风险权限走审批或二次确认;
- 设置临时权限的失效时间;
- 查看变更前后差异和审计记录;
- 撤销角色并验证会话、令牌和缓存及时失效。
权限冲突如何处理
不要默认采用“权限取最大”。显式拒绝、租户边界、合规限制和职责分离应优先于普通允许。产品文档必须写清:
- 多角色是并集还是存在显式拒绝;
- 自定义授权能否覆盖角色;
- 数据范围如何合并;
- 角色层级如何继承;
- 权限变更何时生效;
- 旧会话和下载链接如何失效。
七、假设案例:CRM 合同折扣审批
以下是教学场景,不代表真实客户配置。
需求:销售可以创建折扣申请;区域主管审批 20% 以下折扣;超过 20% 需要财务审批;申请人与最终审批人不能是同一人。
权限拆解
| 主体 | 资源 | 动作 | 数据范围 | 约束 |
|---|---|---|---|---|
| 销售 | discount_request | create/read | 本人创建 | 不能审批 |
| 区域主管 | discount_request | read/approve | 本区域 | 折扣 ≤20%,非本人申请 |
| 财务 | discount_request | read/approve | 全租户 | 折扣 >20%,非本人申请 |
| 审计员 | discount_request | read | 全租户 | 只读,敏感字段脱敏 |
必须测试的反例
- 销售修改请求参数尝试调用审批 API;
- A 区主管输入 B 区申请 ID;
- 主管审批自己创建的申请;
- 将 19% 修改为 25% 后复用旧审批;
- 被移除角色的用户继续使用旧页面或旧令牌;
- 租户 A 的导出任务错误读取租户 B 缓存;
- 审计员从批量导出绕过字段脱敏。
权限验收不能只走正常路径。
八、成员生命周期
权限会随着组织变化:
- 邀请前确认邮箱域、租户和默认角色;
- 入职采用岗位模板,不复制某位旧员工全部权限;
- 转岗时先移除旧职责,再授予新职责;
- 临时项目权限必须有到期日和负责人;
- 离职时撤销会话、令牌、API 密钥和共享链接;
- 定期让客户管理员复核高风险角色和长期未使用权限。
服务账号和 Agent 不应继承某个用户的全部权限。为具体任务授予短期、最小范围的能力,并将实际操作者、授权人和工具调用写入审计记录。相关运行护栏可参考AI Agent 产品指标体系。
九、审计日志设计
一条授权与高风险操作记录至少包含:
- 谁在什么租户发起;
- 代表谁或由哪个服务执行;
- 对什么资源执行什么动作;
- 权限判定结果与命中的策略版本;
- 请求时间、来源和关联 task_id;
- 变更前后摘要;
- 审批、确认与失败原因;
- 是否回滚以及最终状态。
日志本身也包含敏感信息,需要访问控制、保留期限和防篡改设计。
十、上线前测试矩阵
- 无角色、过期角色和未知权限默认拒绝
- 同角色跨租户访问被拒绝
- 页面隐藏与 API 校验一致
- 查看、编辑、删除、导出分别测试
- 本人、团队、部门和全租户范围分别测试
- 字段脱敏不能通过导出或搜索绕过
- 角色继承、冲突和职责分离符合文档
- 权限撤销后会话、缓存和异步任务及时失效
- 高风险操作有确认、审批和审计
- 授权失败不会泄露资源信息
继续学习可以查看B2B 产品经理岗位指南、B2B SaaS 设计项目,或浏览B2B 产品专题。