1. 多租户SaaS概述
1.1 多租户概念
多租户(Multi-Tenancy)是SaaS架构的核心特征,指单个软件实例同时服务于多个租户(Tenant),每个租户拥有独立的业务数据与配置,且彼此逻辑隔离。租户可以是企业、部门或个人用户,在鉴权拦截链路中,租户身份是路由与权限判定的第一要素。
关键定义: 多租户 ≠ 多用户。租户是资源隔离与计费的单位,用户是租户内的操作主体。鉴权拦截链路必须同时校验“租户有效性”与“用户权限”。
1.2 SaaS架构演进
SaaS架构经历了从单体到微服务的演进,不同阶段对鉴权拦截与链路追踪的要求差异显著:
| 阶段 | 架构特征 | 鉴权拦截方式 | 链路追踪难度 |
|---|---|---|---|
| 单体SaaS | 单进程、共享数据库 | Filter拦截器 + ThreadLocal | 低(单进程内完成) |
| 垂直拆分SaaS | 按功能拆分为多个服务 | 网关统一鉴权 + 服务间Token传递 | 中(需跨服务传递上下文) |
| 微服务SaaS | 细粒度服务、独立部署 | API Gateway + 分布式Session + JWT | 高(需全链路追踪与异常捕获) |
| 云原生SaaS | 容器化、Service Mesh、可观测性 | Sidecar代理 + OPA策略引擎 | 极高(需分布式追踪+日志+指标联动) |
课程聚焦: 本课程以微服务SaaS与云原生SaaS为背景,重点解决鉴权拦截链路中异常捕获与分布式追踪的工程难题。
1.3 租户隔离模型
租户隔离模型决定了数据存储与资源分配策略,直接影响鉴权拦截链路的实现复杂度。主流模型分为三种:
- 共享模型(Shared): 所有租户共用同一数据库实例与表结构,通过
tenant_id字段区分。成本最低,但隔离性最弱,鉴权拦截需确保tenant_id不被篡改。 - 独享模型(Isolated): 每个租户拥有独立的数据库实例或Schema。隔离性最强,但资源开销大,鉴权拦截需动态路由到对应数据源。
- 混合模型(Hybrid): 根据租户等级或业务需求,部分租户共享、部分租户独享。鉴权拦截链路需支持动态隔离策略,在运行时判断租户所属模型。
1.4 隔离模型选择矩阵
实际项目中,隔离模型的选择需综合安全等级、合规要求、运维成本与性能四个维度:
| 评估维度 | 共享模型 | 独享模型 | 混合模型 |
|---|---|---|---|
| 数据安全 | 低(依赖应用层隔离) | 高(物理/逻辑隔离) | 中高(按需分配) |
| 合规满足 | 难(如GDPR、金融合规) | 易(独立审计) | 中(需策略配置) |
| 运维成本 | 低(一套环境) | 高(N套环境) | 中(自动化编排) |
| 查询性能 | 中(大表+索引) | 高(小表+无干扰) | 中高(按租户优化) |
| 鉴权复杂度 | 低(统一Filter) | 中(多数据源路由) | 高(动态策略引擎) |
常见陷阱: 共享模型下,若鉴权拦截链路未对
tenant_id做服务端校验,攻击者可伪造租户身份越权访问其他租户数据。必须结合JWT签名与链路追踪日志双重验证。
1.5 鉴权拦截链路中的租户上下文传递
在微服务SaaS架构中,租户上下文(Tenant Context)需在鉴权拦截链路中透传。典型传递方式如下:
# 伪代码:租户上下文传递示例
class TenantContext:
"""线程级租户上下文"""
_tenant_id = None
_user_id = None
@classmethod
def set(cls, tenant_id: str, user_id: str):
cls._tenant_id = tenant_id
cls._user_id = user_id
@classmethod
def get_tenant_id(cls) -> str:
return cls._tenant_id
# 鉴权拦截器
class AuthInterceptor:
def intercept(self, request):
token = request.headers.get('Authorization')
payload = self.verify_jwt(token) # 验证JWT
TenantContext.set(payload['tenant_id'], payload['user_id'])
# 继续链路...
最佳实践: 在微服务SaaS中,建议将
tenant_id放入gRPC Metadata或HTTP Header(如 X-Tenant-ID),并在API网关层统一注入。链路追踪系统(如OpenTelemetry)会自动将Header中的租户信息关联到Span,实现全链路可观测。