feat: finalize core modules and gateway
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
|
||||
/// <summary>
|
||||
/// 数据源名称常量,统一配置键与使用。
|
||||
/// </summary>
|
||||
public static class DatabaseConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认业务库(AppDatabase)。
|
||||
/// </summary>
|
||||
public const string AppDataSource = "AppDatabase";
|
||||
|
||||
/// <summary>
|
||||
/// 身份认证库(IdentityDatabase)。
|
||||
/// </summary>
|
||||
public const string IdentityDataSource = "IdentityDatabase";
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Data;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接角色,用于区分主写与从读连接。
|
||||
/// </summary>
|
||||
public enum DatabaseConnectionRole
|
||||
{
|
||||
/// <summary>
|
||||
/// 主写连接,用于写入或强一致读。
|
||||
/// </summary>
|
||||
Write = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 从读连接,用于只读查询或报表。
|
||||
/// </summary>
|
||||
Read = 2
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Data;
|
||||
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Dapper 查询/命令执行器抽象,封装连接获取与读写路由。
|
||||
/// </summary>
|
||||
public interface IDapperExecutor
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用指定数据源与读写角色执行异步查询,并返回结果。
|
||||
/// </summary>
|
||||
/// <typeparam name="TResult">查询结果类型。</typeparam>
|
||||
/// <param name="dataSourceName">逻辑数据源名称。</param>
|
||||
/// <param name="role">连接角色(读/写)。</param>
|
||||
/// <param name="query">查询委托,提供已打开的连接和取消标记。</param>
|
||||
/// <param name="cancellationToken">取消标记。</param>
|
||||
/// <returns>查询结果。</returns>
|
||||
Task<TResult> QueryAsync<TResult>(
|
||||
string dataSourceName,
|
||||
DatabaseConnectionRole role,
|
||||
Func<IDbConnection, CancellationToken, Task<TResult>> query,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定数据源与读写角色执行异步命令。
|
||||
/// </summary>
|
||||
/// <param name="dataSourceName">逻辑数据源名称。</param>
|
||||
/// <param name="role">连接角色(读/写)。</param>
|
||||
/// <param name="command">命令委托,提供已打开的连接和取消标记。</param>
|
||||
/// <param name="cancellationToken">取消标记。</param>
|
||||
Task ExecuteAsync(
|
||||
string dataSourceName,
|
||||
DatabaseConnectionRole role,
|
||||
Func<IDbConnection, CancellationToken, Task> command,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定数据源及角色的默认命令超时时间(秒)。
|
||||
/// </summary>
|
||||
/// <param name="dataSourceName">逻辑数据源名称。</param>
|
||||
/// <param name="role">连接角色,默认读取从库。</param>
|
||||
/// <returns>命令超时时间(秒)。</returns>
|
||||
int GetDefaultCommandTimeoutSeconds(
|
||||
string dataSourceName,
|
||||
DatabaseConnectionRole role = DatabaseConnectionRole.Read);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 审计实体基类:提供创建、更新时间以及软删除时间。
|
||||
/// </summary>
|
||||
public abstract class AuditableEntityBase : EntityBase, IAuditableEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建时间(UTC)。
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最近一次更新时间(UTC),从未更新时为 null。
|
||||
/// </summary>
|
||||
public DateTime? UpdatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 软删除时间(UTC),未删除时为 null。
|
||||
/// </summary>
|
||||
public DateTime? DeletedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建人用户标识,匿名或系统操作时为 null。
|
||||
/// </summary>
|
||||
public Guid? CreatedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后更新人用户标识,匿名或系统操作时为 null。
|
||||
/// </summary>
|
||||
public Guid? UpdatedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 删除人用户标识(软删除),未删除时为 null。
|
||||
/// </summary>
|
||||
public Guid? DeletedBy { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 实体基类,统一提供主键标识。
|
||||
/// </summary>
|
||||
public abstract class EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 实体唯一标识。
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 审计字段接口:提供创建时间和更新时间字段。
|
||||
/// 审计字段接口:提供创建、更新、删除时间与操作者标识。
|
||||
/// </summary>
|
||||
public interface IAuditableEntity
|
||||
public interface IAuditableEntity : ISoftDeleteEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建时间(UTC)。
|
||||
@@ -14,5 +14,24 @@ public interface IAuditableEntity
|
||||
/// 更新时间(UTC),未更新时为 null。
|
||||
/// </summary>
|
||||
DateTime? UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除时间(UTC),未删除时为 null。
|
||||
/// </summary>
|
||||
new DateTime? DeletedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建人用户标识,匿名或系统操作时为 null。
|
||||
/// </summary>
|
||||
Guid? CreatedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最后更新人用户标识,匿名或系统操作时为 null。
|
||||
/// </summary>
|
||||
Guid? UpdatedBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 删除人用户标识(软删除),未删除时为 null。
|
||||
/// </summary>
|
||||
Guid? DeletedBy { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 软删除实体约定:提供可空的删除时间戳以支持全局过滤。
|
||||
/// </summary>
|
||||
public interface ISoftDeleteEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 删除时间(UTC),未删除时为 null。
|
||||
/// </summary>
|
||||
DateTime? DeletedAt { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 多租户审计实体基类:提供租户标识、审计字段与软删除标记。
|
||||
/// </summary>
|
||||
public abstract class MultiTenantEntityBase : AuditableEntityBase, IMultiTenantEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属租户 ID。
|
||||
/// </summary>
|
||||
public Guid TenantId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace TakeoutSaaS.Shared.Abstractions.Security;
|
||||
|
||||
/// <summary>
|
||||
/// 当前用户访问器:提供与当前请求相关的用户标识信息。
|
||||
/// </summary>
|
||||
public interface ICurrentUserAccessor
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前用户 ID,未登录时为 Guid.Empty。
|
||||
/// </summary>
|
||||
Guid UserId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已登录。
|
||||
/// </summary>
|
||||
bool IsAuthenticated { get; }
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Web.Filters;
|
||||
using TakeoutSaaS.Shared.Web.Security;
|
||||
|
||||
namespace TakeoutSaaS.Shared.Web.Extensions;
|
||||
|
||||
@@ -17,6 +19,7 @@ public static class ServiceCollectionExtensions
|
||||
{
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddEndpointsApiExplorer();
|
||||
services.AddScoped<ICurrentUserAccessor, HttpContextCurrentUserAccessor>();
|
||||
|
||||
services
|
||||
.AddControllers(options =>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
|
||||
namespace TakeoutSaaS.Shared.Web.Security;
|
||||
|
||||
/// <summary>
|
||||
/// 基于 HttpContext 的当前用户访问器。
|
||||
/// </summary>
|
||||
public sealed class HttpContextCurrentUserAccessor : ICurrentUserAccessor
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化访问器。
|
||||
/// </summary>
|
||||
public HttpContextCurrentUserAccessor(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid UserId
|
||||
{
|
||||
get
|
||||
{
|
||||
var principal = _httpContextAccessor.HttpContext?.User;
|
||||
if (principal == null || !principal.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
var identifier = principal.FindFirstValue(ClaimTypes.NameIdentifier)
|
||||
?? principal.FindFirstValue("sub");
|
||||
|
||||
return Guid.TryParse(identifier, out var id) ? id : Guid.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsAuthenticated => UserId != Guid.Empty;
|
||||
}
|
||||
Reference in New Issue
Block a user