4、租户身份与认证:OIDC/OAuth2.0多租户扩展、租户上下文传递、JWT租户声明
在多租户平台中,身份与认证是隔离的第一道防线。本章聚焦于如何基于 OIDC/OAuth2.0 协议实现多租户扩展,确保租户上下文在微服务间正确传递,并通过 JWT 声明承载租户标识,为后续的故障域隔离与路由决策提供可信依据。
4.1 OAuth2.0 / OIDC 多租户扩展模型
标准 OAuth2.0 协议并未原生定义“租户”概念。多租户扩展的核心在于将 issuer(签发者) 与 audience(受众) 与租户标识绑定。常见扩展方式有三种:
| 扩展方式 | 原理 | 适用场景 | 隔离粒度 |
|---|---|---|---|
| 独立 Issuer 模式 | 每个租户拥有独立的 OIDC Issuer URL(如 https://auth.tenant-a.example.com) |
强隔离、合规要求高的金融/医疗租户 | 最高 |
| 路径/子域模式 | 共享 Issuer,通过 URL 路径或子域区分租户(如 https://auth.example.com/tenant-a) |
SaaS 多租户平台,租户数量中等 | 中 |
| Claim 注入模式 | 共享 Issuer,在 的 tenant_id 或 org_id 声明中标识租户 |
轻量级多租户,租户数量大且动态 | 低(依赖验证逻辑) |
推荐实践: 在平台门户中,优先采用 路径/子域模式 + Claim 注入 的组合。Issuer 保持统一,便于证书管理和客户端配置;同时通过 JWT 中的
tenant_id 声明实现细粒度路由。
4.2 租户上下文传递机制
用户认证通过后,租户上下文必须沿请求链路透明传递,避免每个服务重复解析 。传递机制分为 边界传递 和 内部传递 两层:
- 边界传递(Ingress/Gateway): API 网关解析 JWT,提取
tenant_id,将其注入 HTTP Header(如X-Tenant-ID)。 - 内部传递(微服务间): 使用 gRPC Metadata 或 HTTP Header 透传,服务框架(如 Istio/Envoy)通过自定义 Filter 自动注入。
- 异步传递(消息队列): 在消息头中携带租户上下文,消费者消费时重建租户环境。
关键原则: 租户上下文必须作为 不可篡改的请求属性 传递,禁止从用户输入或 URL 参数中读取租户标识,防止租户越权。
4.3 JWT 租户声明设计
JWT 是承载租户上下文的核心载体。标准声明(sub, iss, aud)之外,需要自定义租户相关声明。推荐使用 扁平结构 而非嵌套结构,以降低解析复杂度。
{
"iss": "https://auth.platform.example.com",
"sub": "user-12345",
"aud": "portal-api",
"exp": 1718000000,
"iat": 1717996400,
// 租户声明(自定义)
"tenant_id": "tenant-abc-001",
"tenant_name": "金融事业部",
"tenant_tier": "premium",
"roles": ["admin", "operator"],
"permissions": ["namespace:read", "deployment:create"]
}
| 声明字段 | 类型 | 说明 | 是否必选 |
|---|---|---|---|
tenant_id |
string | 租户唯一标识,用于路由和隔离 | 是 |
tenant_name |
string | 租户可读名称,用于审计和展示 | 推荐 |
tenant_tier |
string | 租户服务等级(如 basic/premium/enterprise) | 推荐 |
roles |
array | 用户在租户内的角色列表 | 推荐 |
permissions |
array | 细粒度权限标识,用于 RBAC 决策 | 可选 |
安全警告: JWT 的 payload 是 Base64 编码而非加密,切勿在声明中放置敏感信息(如数据库密码、)。租户上下文仅用于路由和权限校验,敏感配置应通过 Secret 管理服务获取。
4.4 多租户认证流程(含故障切换)
当认证服务或租户域发生故障时,平台需要具备优雅降级能力。以下流程整合了正常认证与故障切换逻辑:
- 客户端请求:用户携带 Authorization Header 访问平台门户。
- 网关拦截:API 网关验证 JWT 签名(使用 JWKS 端点获取公钥)。
- 租户路由:提取
tenant_id,查询租户路由表,确定目标服务集群。 - 故障检测:若目标集群不可用,网关根据
tenant_tier决定是否切换到备用集群(premium 租户自动切换,basic 租户返回 503)。 - 上下文注入:将
X-Tenant-ID和X-Tenant-Tier注入请求头,转发至后端服务。
4.5 最佳实践与避坑指南
缓存与刷新: 网关应缓存 JWKS 公钥(TTL 建议 1 小时),避免每次请求都拉取。同时,JWT 的
exp 不宜过长(建议 15-30 分钟),配合 Refresh 实现无感续期。
- 租户 ID 不可变: 一旦分配,租户 ID 不得变更。如需重命名,使用
tenant_name字段,tenant_id保持稳定。 - 避免 Header 污染: 内部服务间传递时,使用
X-Tenant-*命名空间,避免与业务 Header 冲突。 - 审计日志: 所有认证和授权决策必须记录
tenant_id、user_id、action和result,便于故障排查。 - 故障切换幂等: 切换至备用集群时,确保 JWT 的
aud声明包含备用集群的标识,避免 被拒绝。