feat: finalize core modules and gateway
This commit is contained in:
@@ -1,48 +1,47 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TakeoutSaaS.Application.Identity.Abstractions;
|
||||
using TakeoutSaaS.Domain.Identity.Entities;
|
||||
using TakeoutSaaS.Domain.Identity.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Common.Extensions;
|
||||
using TakeoutSaaS.Infrastructure.Common.Options;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Options;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
using TakeoutSaaS.Infrastructure.Identity.Services;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using DomainIdentityUser = TakeoutSaaS.Domain.Identity.Entities.IdentityUser;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Identity.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 身份认证基础设施注入
|
||||
/// 身份认证基础设施注入。
|
||||
/// </summary>
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册身份认证基础设施(数据库、Redis、JWT、限流等)
|
||||
/// 注册身份认证基础设施(数据库、Redis、JWT、限流等)。
|
||||
/// </summary>
|
||||
/// <param name="services">服务集合</param>
|
||||
/// <param name="configuration">配置源</param>
|
||||
/// <param name="enableMiniFeatures">是否启用小程序相关依赖(如微信登录)</param>
|
||||
/// <param name="enableAdminSeed">是否启用后台账号初始化</param>
|
||||
/// <param name="services">服务集合。</param>
|
||||
/// <param name="configuration">配置源。</param>
|
||||
/// <param name="enableMiniFeatures">是否启用小程序相关依赖(如微信登录)。</param>
|
||||
/// <param name="enableAdminSeed">是否启用后台账号初始化。</param>
|
||||
/// <returns>服务集合。</returns>
|
||||
/// <exception cref="InvalidOperationException">配置缺失时抛出。</exception>
|
||||
public static IServiceCollection AddIdentityInfrastructure(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
bool enableMiniFeatures = false,
|
||||
bool enableAdminSeed = false)
|
||||
{
|
||||
var dbConnection = configuration.GetConnectionString("IdentityDatabase");
|
||||
if (string.IsNullOrWhiteSpace(dbConnection))
|
||||
{
|
||||
throw new InvalidOperationException("缺少 IdentityDatabase 连接字符串配置");
|
||||
}
|
||||
|
||||
services.AddDbContext<IdentityDbContext>(options => options.UseNpgsql(dbConnection));
|
||||
services.AddDatabaseInfrastructure(configuration);
|
||||
services.AddPostgresDbContext<IdentityDbContext>(DatabaseConstants.IdentityDataSource);
|
||||
|
||||
var redisConnection = configuration.GetConnectionString("Redis");
|
||||
if (string.IsNullOrWhiteSpace(redisConnection))
|
||||
{
|
||||
throw new InvalidOperationException("缺少 Redis 连接字符串配置");
|
||||
throw new InvalidOperationException("缺少 Redis 连接字符串配置。");
|
||||
}
|
||||
|
||||
services.AddStackExchangeRedisCache(options =>
|
||||
@@ -96,4 +95,15 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保数据库连接已配置(Database 节或 ConnectionStrings)。
|
||||
/// </summary>
|
||||
/// <param name="configuration">配置源。</param>
|
||||
/// <param name="dataSourceName">数据源名称。</param>
|
||||
/// <exception cref="InvalidOperationException">未配置时抛出。</exception>
|
||||
private static void EnsureDatabaseConnectionConfigured(IConfiguration configuration, string dataSourceName)
|
||||
{
|
||||
// 保留兼容接口,当前逻辑在 DatabaseConnectionFactory 中兜底并记录日志。
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,30 +5,46 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using TakeoutSaaS.Domain.Identity.Entities;
|
||||
using TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// 身份认证 DbContext,带多租户过滤。
|
||||
/// 身份认证 DbContext,带多租户过滤与审计字段处理。
|
||||
/// </summary>
|
||||
public sealed class IdentityDbContext : TenantAwareDbContext
|
||||
public sealed class IdentityDbContext(
|
||||
DbContextOptions<IdentityDbContext> options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor)
|
||||
{
|
||||
public IdentityDbContext(DbContextOptions<IdentityDbContext> options, ITenantProvider tenantProvider)
|
||||
: base(options, tenantProvider)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 管理后台用户集合。
|
||||
/// </summary>
|
||||
public DbSet<IdentityUser> IdentityUsers => Set<IdentityUser>();
|
||||
|
||||
/// <summary>
|
||||
/// 小程序用户集合。
|
||||
/// </summary>
|
||||
public DbSet<MiniUser> MiniUsers => Set<MiniUser>();
|
||||
|
||||
/// <summary>
|
||||
/// 配置实体模型。
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder">模型构建器。</param>
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
ConfigureIdentityUser(modelBuilder.Entity<IdentityUser>());
|
||||
ConfigureMiniUser(modelBuilder.Entity<MiniUser>());
|
||||
ApplyTenantQueryFilters(modelBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置管理后台用户实体。
|
||||
/// </summary>
|
||||
/// <param name="builder">实体构建器。</param>
|
||||
private static void ConfigureIdentityUser(EntityTypeBuilder<IdentityUser> builder)
|
||||
{
|
||||
builder.ToTable("identity_users");
|
||||
@@ -37,6 +53,9 @@ public sealed class IdentityDbContext : TenantAwareDbContext
|
||||
builder.Property(x => x.DisplayName).HasMaxLength(64).IsRequired();
|
||||
builder.Property(x => x.PasswordHash).HasMaxLength(256).IsRequired();
|
||||
builder.Property(x => x.Avatar).HasMaxLength(256);
|
||||
builder.Property(x => x.TenantId).IsRequired();
|
||||
ConfigureAuditableEntity(builder);
|
||||
ConfigureSoftDeleteEntity(builder);
|
||||
|
||||
var converter = new ValueConverter<string[], string>(
|
||||
v => string.Join(',', v),
|
||||
@@ -55,18 +74,27 @@ public sealed class IdentityDbContext : TenantAwareDbContext
|
||||
.HasConversion(converter)
|
||||
.Metadata.SetValueComparer(comparer);
|
||||
|
||||
builder.HasIndex(x => x.Account).IsUnique();
|
||||
builder.HasIndex(x => x.TenantId);
|
||||
builder.HasIndex(x => new { x.TenantId, x.Account }).IsUnique();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置小程序用户实体。
|
||||
/// </summary>
|
||||
/// <param name="builder">实体构建器。</param>
|
||||
private static void ConfigureMiniUser(EntityTypeBuilder<MiniUser> builder)
|
||||
{
|
||||
builder.ToTable("mini_users");
|
||||
builder.HasKey(x => x.Id);
|
||||
builder.Property(x => x.TenantId).IsRequired();
|
||||
builder.Property(x => x.OpenId).HasMaxLength(128).IsRequired();
|
||||
builder.Property(x => x.UnionId).HasMaxLength(128);
|
||||
builder.Property(x => x.Nickname).HasMaxLength(64).IsRequired();
|
||||
builder.Property(x => x.Avatar).HasMaxLength(256);
|
||||
ConfigureAuditableEntity(builder);
|
||||
ConfigureSoftDeleteEntity(builder);
|
||||
|
||||
builder.HasIndex(x => x.OpenId).IsUnique();
|
||||
builder.HasIndex(x => x.TenantId);
|
||||
builder.HasIndex(x => new { x.TenantId, x.OpenId }).IsUnique();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user