| name | saas-rbac-abac-workflow |
| description | B2B SaaS 多租户 RBAC + ABAC 全流程规范(ASP.NET Core + Vue 3)。 涵盖架构/DBA/后端/前端/安全/测试/DevOps/PM 八角色交付物。 触发词:多租户, 租户隔离, 权限矩阵, RBAC, ABAC, 字段脱敏, 越权, 灰度发布, 数据范围, 权限码. |
SaaS 多租户 RBAC + 轻量 ABAC 全流程规范
分层(长期可用):
- 稳定原则层(10 年级):本文的「核心原则」「权限码三段式」「数据范围标准值」「解释顺序与 deny 优先」「审计全覆盖」「可灰度可回滚」「通用反模式(红线)」——这些是与技术栈无关的安全与多租户铁律。
- 栈实现层(快照,可替换):八个分册中的 ASP.NET Core / EF Core / Vue / SQL 代码模板、接口名(
ITenantResolver 等)、缓存键格式、具体阈值,都是当前实现快照。换语言或框架时,把它们映射到等价机制即可;以仓库实际代码为单一事实来源。
过期处理:只替换栈实现层,原则层保持不动。
按“统一权限表达 + 显式租户隔离 + 分角色交付物”的方式推进需求、设计、开发、测试、发布和回滚。正文只保留执行规则、索引和红线,触发条件由 frontmatter 描述承担。
核心原则(所有角色必须遵守)
- 租户隔离第一:任何查询、写入、缓存、消息、文件存储都必须显式携带
TenantId;禁止"默认共享"。
- 最小权限:默认拒绝;先有
Permission,再挂 Role,最后挂 User;ABAC 仅用于补充 RBAC 无法表达的维度(数据范围、字段可见性、时间/IP/设备)。
- 权限表达统一:权限码采用
模块:资源:动作 三段式(示例 saas:user:read);禁止硬编码散落前后端。
- 数据范围显式化:列表/详情一律走"数据范围过滤器",不得在 UI 层二次裁剪敏感数据。
- 审计全覆盖:权限授予/撤销、敏感字段访问、跨租户操作必须审计,且审计日志本身受 RBAC 保护。
- 可灰度、可回滚:权限模型变更、策略调整必须支持按租户灰度,并保留 1 个版本的回滚脚本。
快速入口
权限码命名
| 段位 | 含义 | 示例 |
|---|
| 1 | 业务模块 | saas, crm, billing |
| 2 | 资源 | user, role, order |
| 3 | 动作 | read, create, update, delete, export, approve |
派生操作追加第 4 段(可选):saas:user:export:sensitive。
数据范围标准值
| 范围 | 说明 |
|---|
Self | 仅本人创建 |
Dept | 本部门 |
DeptAndChild | 本部门及下级 |
Tenant | 本租户(默认最大范围) |
Custom | 自定义组织/部门 ID 集合 |
Global | 仅平台超管,跨租户 |
角色与阶段索引
按“角色 + 阶段”定位分册:
| 阶段 \ 角色 | 架构师 | DBA | 后端 | 前端 | 安全 | 测试 | DevOps | PM |
|---|
| 需求/设计 | A | D | B | F | S | — | — | P |
| 开发 | A | D | B | F | S | — | — | — |
| Code Review | A | D | B | F | S | — | — | — |
| 测试 | — | D | B | F | S | T | — | P |
| 发布 | A | D | B | F | S | T | O | P |
| 运维/运营 | A | D | B | — | S | — | O | P |
字母对应下列分册(均为一级引用):
主工作流
对每一个涉及权限或多租户的任务,按下列顺序推进。任一门禁未通过,不进入下一阶段。
阶段门禁:
- [ ] 1. 需求拆分:PM 产出"权限矩阵草案 + 数据范围假设"(product.md)
- [ ] 2. 架构评审:架构师确认隔离方案与扩展点(architecture.md)
- [ ] 3. 数据建模:DBA 给出 TenantId 策略、索引、迁移脚本(database.md)
- [ ] 4. 后端实现:按模板实现 AuthZ 中间件/策略处理器(backend.md)
- [ ] 5. 前端实现:按指令/路由守卫落地菜单/按钮/数据权限(frontend.md)
- [ ] 6. 安全评审:字段脱敏、审计、越权用例覆盖(security.md)
- [ ] 7. 测试:权限矩阵用例 + 租户隔离回归全绿(testing.md)
- [ ] 8. 发布:灰度 + 回滚预案就绪(devops.md)
- [ ] 9. 运营:监控、审计看板、工单入口就位(devops.md + security.md)
多租户隔离模式
| 模式 | 适用 | 代价 |
|---|
| 共享库共享表(TenantId 列) | 中小 B2B、租户数多、数据量均匀 | 风险:漏加过滤器即越权 |
| 共享库分表(按租户分表) | 单租户数据量大、查询热点明显 | 迁移/索引复杂 |
| 分库(每租户独立库) | 合规/隔离要求高、KA 客户 | 运维成本高、跨租户统计困难 |
| 混合(平台库 + 租户库) | 大 B2B,平台元数据与业务数据分离 | 连接切换/事务边界复杂 |
默认推荐:共享库共享表 + 全局查询过滤器 + TenantId 强制索引。对 KA 客户按需切换到独立库。
ABAC 轻量策略表达
采用“声明式属性 + 条件表达式”模式,不引入重型策略引擎:
{
"policyId": "order.read.dept-scope",
"effect": "allow",
"subject": { "hasPermission": "crm:order:read" },
"resource": "order",
"condition": {
"all": [
{ "eq": ["resource.tenantId", "subject.tenantId"] },
{ "in": ["resource.deptId", "subject.dataScope.deptIds"] },
{ "notIn": ["resource.status", ["Archived"]] }
]
}
}
条件算子仅支持:eq, ne, in, notIn, gt, gte, lt, lte, all, any, not。新增算子需架构师评审。
字段级安全(FLS)
基于本仓库 SysFieldLevelSecurity + FieldMaskStrategy + FieldSecurityTargetType:
- 目标:角色 / 用户 / 部门任一维度
- 策略:
None / FullMask / PartialMask / Hash / Encrypted / Deny
- 实施点:仅在序列化出口与导出出口执行;不得依赖前端过滤
详见 security.md。
通用反模式(红线)
- ❌ 在 Controller 里手写
if (user.TenantId != entity.TenantId) 校验
- ❌ 在前端用
v-if="user.isAdmin" 判定业务权限(仅限 UI 展示)
- ❌ 把权限码拼在前端常量里而不走后端下发
- ❌ 用
SELECT * + 前端脱敏代替 FLS
- ❌ 把
TenantId 放进 URL 路径或 Query 参与鉴权(必须来自可信上下文:JWT/Session)
- ❌ 迁移脚本中无
WHERE TenantId = ? 的批量更新
- ❌ 发布不做灰度、回滚脚本缺失或未演练
快速自检(任何变更合入前)
- [ ] 所有新表含 TenantId 且建立 (TenantId, ...) 复合索引
- [ ] 所有查询走全局过滤器或显式租户上下文
- [ ] 新增权限码已在 PermissionSeed 登记并下发
- [ ] 菜单/按钮/数据范围三层权限齐备
- [ ] 敏感字段走 FLS,非前端裁剪
- [ ] 审计日志覆盖授权变更 + 敏感读写
- [ ] 至少包含:正权限 / 负权限 / 跨租户越权 三类测试
- [ ] 灰度开关与回滚脚本已就绪
进一步阅读
用户需求
以下是用户提供的需求或上下文,请据此判断应进入哪个分册并执行对应规范:
$ARGUMENTS