4. 多租户身份域设计:租户ID绑定、身份池划分、联合认证边界
多租户身份域设计是SaaS权限模型的第一道防线。它定义了租户身份在认证与授权链路中的锚点、分离方式以及跨域信任的契约。本章围绕租户ID绑定、身份池划分和联合认证边界三个核心机制,展开边界定义、分层结构、组件职责、信任链路、选型权衡与落地验收。
4.1 边界定义
身份域设计的边界目标是:确保系统始终知晓“请求来自哪个租户”,并且任何跨租户的身份访问都能在架构层被显式承认或拒绝。边界包含三个维度:
- 租户ID绑定:将用户凭证与唯一租户标识在架构层不可篡改地关联。
- 身份池划分:将用户数据库(或目录服务)按租户逻辑或物理隔离,防止身份泄露。
- 联合认证边界:定义SaaS系统与外部IdP之间信任关系的租户范围。
常见误区:仅依赖JWT中的“tenant_id”字段,而未在网关层进行签名校验与租户ID注入,会导致租户ID伪造攻击。
4.2 分层架构
身份域设计按职责划分为三层,每层处理一个维度的隔离问题:
| 层次 | 职责 | 核心组件 |
|---|---|---|
| 基础设施层 | 租户ID绑定与传输 | 租户ID映射器、API网关 |
| 策略层 | 身份池划分与用户分组 | 身份池管理器、用户目录分区 |
| 边界层 | 联合认证协商与断言校验 | 联合认证网关、IdP代理 |
4.3 组件职责
- 租户ID映射器:在认证入口接收用户凭证时,将其映射为内部统一租户ID(如UUID),并注入到后续请求上下文的
X-Tenant-ID头中。 - 身份池管理器:维护租户与用户目录的映射关系。支持混合模式:小租户共享池、大租户独享池。
- 联合认证网关:对外部IdP发来的SAML断言或OIDC ID Token进行租户校验,提取断言中的
issuer字段,并与预配置的租户IdP白名单比对。 - 会话管理服务:生成绑定了租户ID的会话Token,并确保Token在跨服务调用时不被篡改。
设计原则:租户ID应作为系统内所有服务隐式传递的上下文参数,而非仅在业务代码中显式传递。推荐使用gRPC拦截器或HTTP中间件实现自动注入。
4.4 数据流与控制流:信任链路
典型的认证请求信任链路如下:
- 用户提交凭证到API网关;
- 网关将请求转发给租户ID映射器,映射器根据凭证中的租户标识(如子域名或域名)查询
tenant_registry,获得内部租户ID; - 映射器将内部租户ID写入请求头,并调用身份池管理器进行密码校验;身份池管理器根据租户ID选择对应的用户目录;
- 身份池管理器返回用户身份信息后,会话管理服务生成JWT,其中
sub格式为tenant_id:user_id; - 后续服务接收每一次API调用时,网关校检JWT签名,提取
sub中的租户ID,确保其与请求头X-Tenant-ID一致。
联合认证流程增加了一个边界层步骤:联合认证网关在接收外部IdP的断言后,需校验断言中的issuer是否属于该租户预配置的IdP列表,再提取subject映射为本地用户。
4.5 选型权衡
| 维度 | 方案A:全共享身份池 | 方案B:物理隔离身份池(每租户数据库/目录) |
|---|---|---|
| 运维复杂度 | 低,单实例 | 高,需管理大量连接池 |
| 租户隔离强度 | 依赖应用层过滤 | 物理隔离,安全性高 |
| 性能 | 高吞吐,单点瓶颈 | 分散负载,但跨池查询延迟较高 |
| 推荐场景 | SMB租户,隔离要求低 | 金融/医疗等合规敏感租户 |
联合认证同样需要权衡:SAML成熟度高但XML冗长、手工配置复杂;OIDC轻量、支持动态发现,但要求SaaS系统支持OIDC RP角色。建议视租户IdP主流类型决定,并通过联合认证网关做协议适配。
4.6 风险点
- 租户ID劫持:如果网关未能校验JWT中的租户ID与请求的
X-Tenant-ID头的一致性,攻击者可截获他人JWT,冒充租户。 - 身份池性能雪崩:某个高流量租户的身份请求占满共享连接池,导致其他租户认证失败。解决方案是客户端按租户配置独立连接池,或使用隔离的写入队列。
- 联合认证信任链断裂:外部IdP的证书轮换未同步,或IdP元数据更新延迟,导致合法用户无法登录。需实现自动元数据轮询与验证。
4.7 落地步骤
- 定义租户ID规范:确定租户ID格式(UUID v4或雪花ID),并创建
tenant_registry表存储租户IdP元数据、身份池连接字符串。 - 实现租户ID注入中间件:在网关层解析子域名/请求头,注入
X-Tenant-ID,并对所有内部请求强制校验该头是否存在。 - 划分身份池:按租户规模选择共享或隔离池,配置连接池策略。大租户独享池需额外创建数据库/目录实例。
- 配置联合认证网关:为每个租户录入IdP元数据(
Entity ID、证书、SSO端点),并实现断言校验逻辑。 - 编写信任链路断言测试:模拟正常认证、跨租户Cookie攻击、联合断言篡改三种场景,验证边界是否拦截。
4.8 验收标准
- 每个认证请求必须携带不可篡改的租户ID,验证方式为:JWT中的
sub前缀与X-Tenant-ID头严格一致。 - 身份池隔离测试:租户A的用户无法通过修改请求头中的
tenant_id获取租户B的数据。 - 联合认证欺诈测试:伪造IdP断言(使用错误的
issuer)应被联合认证网关拒绝,并返回401。 - 混合池切换验证:从共享池迁移到独享池后,用户无须重新登录,仅需修改
tenant_registry中该租户的连接字符串。
关键收获:多租户身份域设计的本质是在认证层做租户锚定。租户ID绑定解决了“谁”和“属于谁”的问题;身份池划分解决了“用户数据放哪里”的问题;联合认证边界则解决了“对外信任如何约束”的问题。三者形成一条完整信任链路。