chore: 提交当前变更

This commit is contained in:
2025-11-23 12:47:29 +08:00
parent cd52131c34
commit 429d4fb747
46 changed files with 1864 additions and 63 deletions

View File

@@ -0,0 +1,12 @@
namespace TakeoutSaaS.Shared.Abstractions.Entities;
/// <summary>
/// 多租户实体约定:所有持久化实体须包含租户标识字段。
/// </summary>
public interface IMultiTenantEntity
{
/// <summary>
/// 所属租户 ID。
/// </summary>
Guid TenantId { get; set; }
}

View File

@@ -0,0 +1,12 @@
namespace TakeoutSaaS.Shared.Abstractions.Tenancy;
/// <summary>
/// 租户上下文访问器:用于在请求生命周期内读写当前租户上下文。
/// </summary>
public interface ITenantContextAccessor
{
/// <summary>
/// 获取或设置当前租户上下文。
/// </summary>
TenantContext? Current { get; set; }
}

View File

@@ -1,14 +1,12 @@
namespace TakeoutSaaS.Shared.Abstractions.Tenancy;
/// <summary>
/// 租户提供者接口:用于取当前请求的租户标识
/// 租户提供者:用于在各层读取当前请求绑定的租户 ID
/// </summary>
public interface ITenantProvider
{
/// <summary>
/// 获取当前请求的租户 ID。
/// 获取当前租户 ID,未解析时返回 Guid.Empty
/// </summary>
/// <returns>租户 ID如果未设置则返回 Guid.Empty</returns>
Guid GetCurrentTenantId();
}

View File

@@ -0,0 +1,12 @@
namespace TakeoutSaaS.Shared.Abstractions.Tenancy;
/// <summary>
/// 多租户相关通用常量。
/// </summary>
public static class TenantConstants
{
/// <summary>
/// HttpContext.Items 中租户上下文的键名。
/// </summary>
public const string HttpContextItemKey = "__tenant_context";
}

View File

@@ -0,0 +1,45 @@
namespace TakeoutSaaS.Shared.Abstractions.Tenancy;
/// <summary>
/// 租户上下文:封装当前请求解析得到的租户标识、编号及解析来源。
/// </summary>
public sealed class TenantContext
{
/// <summary>
/// 未解析到租户时的默认上下文。
/// </summary>
public static TenantContext Empty { get; } = new(Guid.Empty, null, "unresolved");
/// <summary>
/// 初始化租户上下文。
/// </summary>
/// <param name="tenantId">租户 ID</param>
/// <param name="tenantCode">租户编码(可选)</param>
/// <param name="source">解析来源</param>
public TenantContext(Guid tenantId, string? tenantCode, string source)
{
TenantId = tenantId;
TenantCode = tenantCode;
Source = source;
}
/// <summary>
/// 当前租户 ID未解析时为 Guid.Empty。
/// </summary>
public Guid TenantId { get; }
/// <summary>
/// 当前租户编码(例如子域名或业务编码),可为空。
/// </summary>
public string? TenantCode { get; }
/// <summary>
/// 租户解析来源Header、Host、Token 等)。
/// </summary>
public string Source { get; }
/// <summary>
/// 是否已成功解析到租户。
/// </summary>
public bool IsResolved => TenantId != Guid.Empty;
}

View File

@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Http;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Shared.Web.Security;
/// <summary>
/// HttpContext 租户扩展方法。
/// </summary>
public static class TenantHttpContextExtensions
{
/// <summary>
/// 获取 HttpContext.Items 中缓存的租户上下文。
/// </summary>
/// <param name="context">当前 HttpContext</param>
/// <returns>租户上下文,若不存在则返回 null</returns>
public static TenantContext? GetTenantContext(this HttpContext? context)
{
if (context == null)
{
return null;
}
if (context.Items.TryGetValue(TenantConstants.HttpContextItemKey, out var value) &&
value is TenantContext tenantContext)
{
return tenantContext;
}
return null;
}
}