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 数据流与控制流:信任链路

典型的认证请求信任链路如下:

  1. 用户提交凭证到API网关;
  2. 网关将请求转发给租户ID映射器,映射器根据凭证中的租户标识(如子域名或域名)查询tenant_registry,获得内部租户ID;
  3. 映射器将内部租户ID写入请求头,并调用身份池管理器进行密码校验;身份池管理器根据租户ID选择对应的用户目录;
  4. 身份池管理器返回用户身份信息后,会话管理服务生成JWT,其中sub格式为tenant_id:user_id;
  5. 后续服务接收每一次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 落地步骤

  1. 定义租户ID规范:确定租户ID格式(UUID v4或雪花ID),并创建tenant_registry表存储租户IdP元数据、身份池连接字符串。
  2. 实现租户ID注入中间件:在网关层解析子域名/请求头,注入X-Tenant-ID,并对所有内部请求强制校验该头是否存在。
  3. 划分身份池:按租户规模选择共享或隔离池,配置连接池策略。大租户独享池需额外创建数据库/目录实例。
  4. 配置联合认证网关:为每个租户录入IdP元数据(Entity ID、证书、SSO端点),并实现断言校验逻辑。
  5. 编写信任链路断言测试:模拟正常认证、跨租户Cookie攻击、联合断言篡改三种场景,验证边界是否拦截。

4.8 验收标准

  • 每个认证请求必须携带不可篡改的租户ID,验证方式为:JWT中的sub前缀与X-Tenant-ID头严格一致。
  • 身份池隔离测试:租户A的用户无法通过修改请求头中的tenant_id获取租户B的数据。
  • 联合认证欺诈测试:伪造IdP断言(使用错误的issuer)应被联合认证网关拒绝,并返回401。
  • 混合池切换验证:从共享池迁移到独享池后,用户无须重新登录,仅需修改tenant_registry中该租户的连接字符串。
关键收获:多租户身份域设计的本质是在认证层做租户锚定。租户ID绑定解决了“谁”和“属于谁”的问题;身份池划分解决了“用户数据放哪里”的问题;联合认证边界则解决了“对外信任如何约束”的问题。三者形成一条完整信任链路。
多租户身份域信任链路 租户A用户 租户B用户 外部IdP (A) 外部IdP (B) API网关 + 租户ID映射器 (子域名解析/JWT校检) 身份池管理器 (连接路由/池划分) 共享池 独享池A 独享池B 联合认证网关 (断言校验/IdP白名单) 信任链路说明: ① 网关注入X-Tenant-ID;② 身份池管理器按租户ID路由到正确池; ③ 联合认证网关通过IdP白名单确保外部断言只属于指定租户;④ 整个链路要求JWT的sub字段包含租户ID前缀。