Files
TakeoutSaaS.TenantApi/src/Infrastructure/TakeoutSaaS.Infrastructure/Identity/Persistence/IdentityDbContext.cs

247 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using MassTransit;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Infrastructure.Common.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
/// <summary>
/// 身份认证 DbContext带多租户过滤与审计字段处理。
/// </summary>
public sealed class IdentityDbContext(
DbContextOptions<IdentityDbContext> options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
/// <summary>
/// 管理后台用户集合。
/// </summary>
public DbSet<IdentityUser> IdentityUsers => Set<IdentityUser>();
/// <summary>
/// 小程序用户集合。
/// </summary>
public DbSet<MiniUser> MiniUsers => Set<MiniUser>();
/// <summary>
/// 角色集合。
/// </summary>
public DbSet<Role> Roles => Set<Role>();
/// <summary>
/// 角色模板集合(系统级)。
/// </summary>
public DbSet<RoleTemplate> RoleTemplates => Set<RoleTemplate>();
/// <summary>
/// 角色模板权限集合。
/// </summary>
public DbSet<RoleTemplatePermission> RoleTemplatePermissions => Set<RoleTemplatePermission>();
/// <summary>
/// 权限集合。
/// </summary>
public DbSet<Permission> Permissions => Set<Permission>();
/// <summary>
/// 用户-角色关系。
/// </summary>
public DbSet<UserRole> UserRoles => Set<UserRole>();
/// <summary>
/// 角色-权限关系。
/// </summary>
public DbSet<RolePermission> RolePermissions => Set<RolePermission>();
/// <summary>
/// 菜单定义集合。
/// </summary>
public DbSet<MenuDefinition> MenuDefinitions => Set<MenuDefinition>();
/// <summary>
/// 配置实体模型。
/// </summary>
/// <param name="modelBuilder">模型构建器。</param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
ConfigureIdentityUser(modelBuilder.Entity<IdentityUser>());
ConfigureMiniUser(modelBuilder.Entity<MiniUser>());
ConfigureRole(modelBuilder.Entity<Role>());
ConfigureRoleTemplate(modelBuilder.Entity<RoleTemplate>());
ConfigureRoleTemplatePermission(modelBuilder.Entity<RoleTemplatePermission>());
ConfigurePermission(modelBuilder.Entity<Permission>());
ConfigureUserRole(modelBuilder.Entity<UserRole>());
ConfigureRolePermission(modelBuilder.Entity<RolePermission>());
ConfigureMenuDefinition(modelBuilder.Entity<MenuDefinition>());
modelBuilder.AddOutboxMessageEntity();
modelBuilder.AddOutboxStateEntity();
ApplyTenantQueryFilters(modelBuilder);
}
/// <summary>
/// 配置管理后台用户实体。
/// </summary>
/// <param name="builder">实体构建器。</param>
private static void ConfigureIdentityUser(EntityTypeBuilder<IdentityUser> builder)
{
builder.ToTable("identity_users");
builder.HasKey(x => x.Id);
builder.Property(x => x.Account).HasMaxLength(64).IsRequired();
builder.Property(x => x.DisplayName).HasMaxLength(64).IsRequired();
builder.Property(x => x.PasswordHash).HasMaxLength(256).IsRequired();
builder.Property(x => x.Phone).HasMaxLength(32);
builder.Property(x => x.Email).HasMaxLength(128);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.FailedLoginCount).IsRequired();
builder.Property(x => x.LockedUntil);
builder.Property(x => x.LastLoginAt);
builder.Property(x => x.MustChangePassword).IsRequired();
builder.Property(x => x.Avatar).HasColumnType("text");
builder.Property(x => x.RowVersion)
.IsRowVersion()
.IsConcurrencyToken()
.HasColumnType("bytea");
builder.Property(x => x.TenantId).IsRequired();
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => new { x.TenantId, x.Account }).IsUnique();
builder.HasIndex(x => new { x.TenantId, x.Phone })
.IsUnique()
.HasFilter("\"Phone\" IS NOT NULL");
builder.HasIndex(x => new { x.TenantId, x.Email })
.IsUnique()
.HasFilter("\"Email\" IS NOT NULL");
}
/// <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).HasColumnType("text");
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => new { x.TenantId, x.OpenId }).IsUnique();
}
private static void ConfigureRole(EntityTypeBuilder<Role> builder)
{
builder.ToTable("roles");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Code).HasMaxLength(64).IsRequired();
builder.Property(x => x.Description).HasMaxLength(256);
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
}
private static void ConfigurePermission(EntityTypeBuilder<Permission> builder)
{
builder.ToTable("permissions");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.ParentId).IsRequired();
builder.Property(x => x.SortOrder).IsRequired();
builder.Property(x => x.Type).HasMaxLength(16).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Code).HasMaxLength(128).IsRequired();
builder.Property(x => x.Description).HasMaxLength(256);
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => new { x.TenantId, x.ParentId, x.SortOrder });
builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
}
private static void ConfigureRoleTemplate(EntityTypeBuilder<RoleTemplate> builder)
{
builder.ToTable("role_templates");
builder.HasKey(x => x.Id);
builder.Property(x => x.TemplateCode).HasMaxLength(64).IsRequired();
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.Description).HasMaxLength(256);
builder.Property(x => x.IsActive).IsRequired();
ConfigureAuditableEntity(builder);
builder.HasIndex(x => x.TemplateCode).IsUnique();
}
private static void ConfigureRoleTemplatePermission(EntityTypeBuilder<RoleTemplatePermission> builder)
{
builder.ToTable("role_template_permissions");
builder.HasKey(x => x.Id);
builder.Property(x => x.RoleTemplateId).IsRequired();
builder.Property(x => x.PermissionCode).HasMaxLength(128).IsRequired();
ConfigureAuditableEntity(builder);
builder.HasIndex(x => new { x.RoleTemplateId, x.PermissionCode }).IsUnique();
}
private static void ConfigureUserRole(EntityTypeBuilder<UserRole> builder)
{
builder.ToTable("user_roles");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.UserId).IsRequired();
builder.Property(x => x.RoleId).IsRequired();
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => new { x.TenantId, x.UserId, x.RoleId }).IsUnique();
}
private static void ConfigureRolePermission(EntityTypeBuilder<RolePermission> builder)
{
builder.ToTable("role_permissions");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.RoleId).IsRequired();
builder.Property(x => x.PermissionId).IsRequired();
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => new { x.TenantId, x.RoleId, x.PermissionId }).IsUnique();
}
private static void ConfigureMenuDefinition(EntityTypeBuilder<MenuDefinition> builder)
{
builder.ToTable("menu_definitions");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.ParentId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Path).HasMaxLength(256).IsRequired();
builder.Property(x => x.Component).HasMaxLength(256).IsRequired();
builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
builder.Property(x => x.Icon).HasMaxLength(64);
builder.Property(x => x.Link).HasMaxLength(512);
builder.Property(x => x.SortOrder).IsRequired();
builder.Property(x => x.RequiredPermissions).HasMaxLength(1024);
builder.Property(x => x.MetaPermissions).HasMaxLength(1024);
builder.Property(x => x.MetaRoles).HasMaxLength(1024);
builder.Property(x => x.AuthListJson).HasColumnType("text");
ConfigureAuditableEntity(builder);
ConfigureSoftDeleteEntity(builder);
builder.HasIndex(x => new { x.TenantId, x.ParentId, x.SortOrder });
}
}