MoneyTree.MultiTenancy 1.0.5
MoneyTree.MultiTenancy 多租户
📋 概述
MoneyTree.MultiTenancy 提供可插拔的多租户中间件,支持从多种来源(HTTP 头、子域名、JWT Claim)自动解析租户标识,并提供租户上下文管理、租户信息存储和组合策略。结合 MoneyTree.EFCore.MultiTenancy 扩展包可实现数据库级别的自动租户数据隔离。
| 属性 | 说明 |
|---|---|
| NuGet 包 | MoneyTree.MultiTenancy |
| 外部依赖 | MoneyTree.Core |
| 定位 | 可插拔的多租户中间件 |
🏗️ 项目文件结构
MoneyTree.MultiTenancy/
├── MoneyTree.MultiTenancy.csproj
├── GlobalUsings.cs
├── TenantInfo.cs # 租户信息模型
├── Abstractions/
│ ├── IMultiTenant.cs # 多租户实体标记接口
│ ├── ITenantContext.cs # 租户上下文接口
│ ├── ITenantContextAccessor.cs # 租户上下文访问器
│ ├── ITenantResolutionStrategy.cs # 租户解析策略接口
│ └── ITenantStore.cs # 租户信息存储接口
├── Core/
│ ├── MultiTenantEntity.cs # 多租户实体/聚合根基类
│ ├── TenantContext.cs # 租户上下文默认实现
│ └── TenantContextAccessor.cs # 租户上下文访问器实现
├── Resolution/
│ ├── HeaderResolutionStrategy.cs # HTTP 头解析策略
│ ├── HostResolutionStrategy.cs # 子域名解析策略
│ ├── ClaimResolutionStrategy.cs # JWT Claim 解析策略
│ ├── DefaultTenantResolutionStrategy.cs # 默认租户策略(兜底)
│ └── CompositeResolutionStrategy.cs # 组合策略(多策略链式尝试)
├── Store/
│ └── InMemoryTenantStore.cs # 内存租户信息存储
├── Middleware/
│ └── MultiTenancyMiddleware.cs # 多租户 HTTP 中间件
└── Extensions/
├── MultiTenancyBuilder.cs # 流畅配置构造器
└── MultiTenancyExtensions.cs # DI 注册扩展
🎯 核心能力
| 能力 | 说明 |
|---|---|
| 租户解析 | 自动从请求中提取租户标识 |
| 上下文管理 | Scoped 生命周期的 TenantContext,随请求自动创建和清理 |
| 实体标记 | IMultiTenant 接口标记需要租户隔离的实体 |
| 策略组合 | 多策略组合,按优先级依次尝试解析 |
| 租户验证 | 检出过期/停用的租户并拒绝请求 |
| 灵活存储 | 内置 InMemoryTenantStore,可通过 ITenantStore 扩展 |
🚀 快速开始
基础配置
// Program.cs
using MoneyTree.MultiTenancy.Extensions;
var builder = WebApplication.CreateBuilder(args);
// 最简配置:Header 策略 + 内存存储 + 默认租户
builder.Services.AddMoneyTreeMultiTenancy();
var app = builder.Build();
app.UseMoneyTreeMultiTenancy();
app.Run();
自定义配置
builder.Services.AddMoneyTreeMultiTenancy(mt =>
{
mt.UseHeader("X-Tenant-Id") // 从请求头解析
.UseHost() // 从子域名解析
.UseClaim("tenant_id") // 从 JWT Claim 解析
.UseDefault("default-tenant") // 解析失败时的默认租户
.UseInMemoryStore(store => // 内存存储
store.Seed(new TenantInfo
{
Id = "tenant-001",
Name = "企业客户A",
ExpiresAt = DateTime.UtcNow.AddYears(1)
}));
});
📖 使用示例
租户解析策略
| 策略 | NuGet 方法 | 示例 | 说明 |
|---|---|---|---|
| Header | UseHeader("X-Tenant-Id") |
X-Tenant-Id: tenant-001 |
从 HTTP 请求头解析 |
| Host | UseHost() |
tenant-001.example.com |
从子域名解析 |
| Claim | UseClaim("tenant_id") |
JWT tenant_id claim |
从 Token 中解析 |
| Default | UseDefault("default") |
所有策略失败后兜底 | 兜底默认租户 |
标记多租户实体
// 方式一:实现 IMultiTenant 接口
public class Order : AggregateRoot, IMultiTenant
{
public string? TenantId { get; set; }
public string OrderNumber { get; set; } = string.Empty;
}
// 方式二:继承 MultiTenantEntity 基类
public class Product : MultiTenantEntity
{
public string Name { get; set; } = string.Empty;
}
在服务中使用租户上下文
public class OrderService
{
[Inject] public ITenantContextAccessor TenantAccessor { get; private set; } = default!;
public async Task<List<Order>> GetOrdersAsync()
{
var tenantId = TenantAccessor.TenantContext?.TenantId;
// 查询自动应用租户筛选(需配合 MoneyTree.EFCore.MultiTenancy)
return await _db.Orders.ToListAsync();
}
}
TenantInfo 模型
| 属性 | 类型 | 说明 |
|---|---|---|
| Id | string |
租户唯一标识 |
| Name | string |
租户名称 |
| DisplayName | string |
租户显示名称 |
| IsActive | bool |
是否活跃(非活跃租户的请求将被拒绝) |
| CreatedAt | DateTime |
租户创建时间 |
| ExpiresAt | DateTime? |
租户过期时间 |
| Properties | Dictionary<string, string> |
自定义属性(如连接字符串、存储配额) |
🛡️ 中间件执行流程
HTTP 请求到达
│
▼
MultiTenancyMiddleware
│
├── 1. 通过 ITenantResolutionStrategy 解析 TenantId
│ ├── Header → Host → Claim → Default(按策略链依次尝试)
│
├── 2. 通过 ITenantStore 获取 TenantInfo
│
├── 3. 验证租户状态
│ ├── IsActive == false → 返回 403
│ ├── IsExpired() == true → 返回 403
│
├── 4. 创建 TenantContext(Scoped)
│
└── 5. 继续执行请求管道
🔗 与 EF Core 多租户联动
MoneyTree.EFCore.MultiTenancy 扩展包自动集成此模块,实现:
- TenantFilterInterceptor:查询时自动添加
WHERE TenantId = @currentTenantId - TenantSaveChangesInterceptor:新增实体时自动填充
TenantId - IgnoreTenantFilter():管理后台跨租户查询
Showing the top 20 packages that depend on MoneyTree.MultiTenancy.
| Packages | Downloads |
|---|---|
|
MoneyTree.Audit.Shared
MoneyTree Audit 共享层。提供审计实体模型、EF Core 配置和 EfAuditLogger 直写实现。业务服务引用此包后,可通过独立 DbContext 直写审计表,审计日志不受业务事务回滚影响。
|
2 |
|
MoneyTree.EFCore.MultiTenancy
MoneyTree Framework EF Core 多租户扩展包。提供租户筛选拦截器、租户自动填充拦截器。
|
2 |
|
MoneyTree.Audit.Shared
MoneyTree Audit 共享层。提供审计实体模型、EF Core 配置和 EfAuditLogger 直写实现。业务服务引用此包后,可通过 DbContext 在同事务中直接写入审计表,零网络调用、强一致、实时。
|
1 |
|
MoneyTree.EFCore.MultiTenancy
MoneyTree Framework EF Core 多租户扩展包。提供租户筛选拦截器、租户自动填充拦截器。
|
1 |
.NET 10.0
- MoneyTree.Core (>= 1.0.4)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.3.11)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Options (>= 10.0.10)