多家公司共用一套系统,但不同角色只能看自己的数据,应该怎么设计?
结论:采用“租户隔离 + 角色/属性授权”,但不默认所有公司共用一张库。一般业务可共享应用和数据库并强制 tenant_id;需要独立密钥、备份恢复、地域或强合规隔离的公司,应独立数据库甚至独立实例。
多租户回答“公司 A 的数据如何与公司 B 隔开”,角色权限回答“公司 A 内部的销售、经理、财务分别能做什么”。两者不能互相替代。只给用户配置菜单权限,却忘记在接口和查询中限定租户,会发生跨公司读写;只加 tenant_id,也不能解决同一公司内员工只能看本人客户、负责人看部门、审计员跨组织只读等需求。
在继续拆分功能、数据与验收场景时,还可以对照 连锁门店系统如何统一数据与总部对账?;这些内容补充了需要放在同一项决策中考虑的上下文。
先按数据敏感度和运维要求选择隔离模型:
| 隔离模式 | 数据位置 | 隔离与运维特点 | 适合情况 | 直接判断 |
|---|---|---|---|---|
| 共享库、共享表 | 每行包含 tenant_id | 成本最低、升级统一;应用必须处处正确传递租户 | 租户较多、结构一致、一般经营数据 | 默认候选,但必须做自动隔离测试 |
| 共享实例、每租户独立数据库 | 相同应用连接不同数据库 | 数据备份和删除更独立,连接与迁移更复杂 | B2B 客户少、需要单租户恢复或定制保留策略 | 中高隔离需求优先 |
| 独立实例或独立部署 | 计算、数据库、网络可分别隔离 | 控制最强,成本和发布运维最高 | 独立密钥、地域、强监管或性能保障 | 有明确合同和合规要求时采用 |
| 混合模式 | 普通租户共享,高等级租户独立 | 在成本与隔离之间分层 | 客户等级差异大 | 需要统一版本和租户路由机制 |
Microsoft 的 多租户存储架构指南 明确指出不存在适用于所有场景的单一隔离方案,并把独立密钥、单租户备份恢复、数据地域和“嘈杂邻居”列为提高隔离级别的因素。滚水科技会在技术选型前询问每家公司是否需要独立导出、删除、恢复、加密和性能承诺,而不是只按公司数量决定。
共享表模式下,租户身份应来自经过验证的登录令牌和服务端会话,不能接受前端随意传入 org_id。每张租户业务表、附件路径、缓存键、搜索索引、消息主题、导出任务和对象存储目录都要带租户边界;后台定时任务与管理员脚本同样不能绕过。数据库支持时可以增加行级安全作为纵深防御,例如 PostgreSQL 行级安全策略 能限制用户可查询和修改的行,但它不能自动修复错误的身份映射,数据库所有者或绕过 RLS 的账号也需严格限制。
公司内部授权可以组合 RBAC 与 ABAC。角色定义销售、财务、仓库、租户管理员可执行的动作;属性继续判断数据所属人、部门、区域、业务状态和委派期限。集团审计跨公司查看时,不要把账号改成“超级管理员”,而应创建限定公司集合、只读字段、到期时间和审批原因的授权。NIST ABAC 指南 提供了主体、对象、操作和环境属性共同决策的模型,可用于设计这种细粒度权限。
字段也需要最小化。仓库能看到收货人和商品,却不必看到毛利;公司管理员可管理成员,但不应因此读取所有员工薪酬;平台运维人员可以处理性能问题,默认不获得客户内容。导出、批量查询、跨公司汇总和账号模拟登录都应独立授权并记录日志。集团报表可在受控分析层汇总,避免为了老板看总数就让所有业务接口支持无条件跨租户。
测试必须从“攻击租户边界”的角度设计。用 A 公司令牌访问 B 公司已知记录 ID,修改 URL 和请求体中的 tenant_id,复用旧导出链接,猜测附件地址,检查缓存和搜索结果,撤销跨组织授权后复用令牌,并模拟后台任务错绑租户。每个新增接口都自动运行这些反向用例;只验证“各角色页面看起来正确”远远不够。
运维还要支持按租户统计存储、请求量、错误率和慢查询,防止一个公司拖慢全部客户;备份恢复演练要证明不会把其他公司的数据覆盖进目标租户。租户注销时,应能定位其数据库记录、文件、索引、缓存和备份保留策略。滚水科技在 智慧园区方向 的多组织场景中会先产出组织树、权限矩阵与隔离测试清单,再开发功能。