docs: add xml comments and update ignore rules
This commit is contained in:
@@ -22,38 +22,52 @@ namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
/// </summary>
|
||||
public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger<IdentityDataSeeder> logger) : IHostedService
|
||||
{
|
||||
/// <summary>
|
||||
/// 执行后台账号与权限种子。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消标记。</param>
|
||||
/// <returns>异步任务。</returns>
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 创建作用域并解析依赖
|
||||
using var scope = serviceProvider.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<IdentityDbContext>();
|
||||
var options = scope.ServiceProvider.GetRequiredService<IOptions<AdminSeedOptions>>().Value;
|
||||
var passwordHasher = scope.ServiceProvider.GetRequiredService<IPasswordHasher<DomainIdentityUser>>();
|
||||
var tenantContextAccessor = scope.ServiceProvider.GetRequiredService<ITenantContextAccessor>();
|
||||
|
||||
// 2. 校验功能开关
|
||||
if (!options.Enabled)
|
||||
{
|
||||
logger.LogInformation("AdminSeed 已禁用,跳过后台账号初始化");
|
||||
return;
|
||||
}
|
||||
// 3. 确保数据库已迁移
|
||||
await context.Database.MigrateAsync(cancellationToken);
|
||||
|
||||
// 4. 校验账号配置
|
||||
if (options.Users is null or { Count: 0 })
|
||||
{
|
||||
logger.LogInformation("AdminSeed 未配置账号,跳过后台账号初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 写入角色模板
|
||||
await SeedRoleTemplatesAsync(context, options.RoleTemplates, cancellationToken);
|
||||
|
||||
// 6. 逐个账号处理
|
||||
foreach (var userOptions in options.Users)
|
||||
{
|
||||
// 6.1 进入租户作用域
|
||||
using var tenantScope = EnterTenantScope(tenantContextAccessor, userOptions.TenantId);
|
||||
// 6.2 查询账号并收集配置
|
||||
var user = await context.IdentityUsers.FirstOrDefaultAsync(x => x.Account == userOptions.Account, cancellationToken);
|
||||
var roles = NormalizeValues(userOptions.Roles);
|
||||
var permissions = NormalizeValues(userOptions.Permissions);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
// 6.3 创建新账号
|
||||
user = new DomainIdentityUser
|
||||
{
|
||||
Id = 0,
|
||||
@@ -69,6 +83,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
}
|
||||
else
|
||||
{
|
||||
// 6.4 更新既有账号
|
||||
user.DisplayName = userOptions.DisplayName;
|
||||
user.TenantId = userOptions.TenantId;
|
||||
user.MerchantId = userOptions.MerchantId;
|
||||
@@ -76,7 +91,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
logger.LogInformation("已更新后台账号 {Account}", user.Account);
|
||||
}
|
||||
|
||||
// 确保角色存在
|
||||
// 6.5 确保角色存在
|
||||
var existingRoles = await context.Roles
|
||||
.Where(r => r.TenantId == userOptions.TenantId && roles.Contains(r.Code))
|
||||
.ToListAsync(cancellationToken);
|
||||
@@ -97,7 +112,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
});
|
||||
}
|
||||
|
||||
// 确保权限存在
|
||||
// 6.6 确保权限存在
|
||||
var existingPermissions = await context.Permissions
|
||||
.Where(p => p.TenantId == userOptions.TenantId && permissions.Contains(p.Code))
|
||||
.ToListAsync(cancellationToken);
|
||||
@@ -118,9 +133,10 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
});
|
||||
}
|
||||
|
||||
// 6.7 保存基础角色/权限
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 重新加载角色/权限以获取 Id
|
||||
// 6.8 重新加载角色/权限以获取 Id
|
||||
var roleEntities = await context.Roles
|
||||
.Where(r => r.TenantId == userOptions.TenantId && roles.Contains(r.Code))
|
||||
.ToListAsync(cancellationToken);
|
||||
@@ -128,7 +144,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
.Where(p => p.TenantId == userOptions.TenantId && permissions.Contains(p.Code))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// 重置用户角色
|
||||
// 6.9 重置用户角色
|
||||
var existingUserRoles = await context.UserRoles
|
||||
.Where(ur => ur.TenantId == userOptions.TenantId && ur.UserId == user.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
@@ -191,6 +207,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
continue;
|
||||
}
|
||||
|
||||
// 6.10 绑定角色与权限
|
||||
await context.RolePermissions.AddAsync(new DomainRolePermission
|
||||
{
|
||||
TenantId = userOptions.TenantId,
|
||||
@@ -209,9 +226,15 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 最终保存
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止生命周期时的清理(此处无需处理)。
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消标记。</param>
|
||||
/// <returns>已完成任务。</returns>
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
private static async Task SeedRoleTemplatesAsync(
|
||||
@@ -219,23 +242,28 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
IList<RoleTemplateSeedOptions> templates,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 空集合直接返回
|
||||
if (templates is null || templates.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 逐个处理模板
|
||||
foreach (var templateOptions in templates)
|
||||
{
|
||||
// 2.1 校验必填字段
|
||||
if (string.IsNullOrWhiteSpace(templateOptions.TemplateCode) || string.IsNullOrWhiteSpace(templateOptions.Name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2.2 查询现有模板
|
||||
var code = templateOptions.TemplateCode.Trim();
|
||||
var existing = await context.RoleTemplates.FirstOrDefaultAsync(x => x.TemplateCode == code, cancellationToken);
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
// 2.3 新增模板
|
||||
existing = new DomainRoleTemplate
|
||||
{
|
||||
TemplateCode = code,
|
||||
@@ -249,6 +277,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2.4 更新模板
|
||||
existing.Name = templateOptions.Name.Trim();
|
||||
existing.Description = templateOptions.Description;
|
||||
existing.IsActive = templateOptions.IsActive;
|
||||
@@ -256,13 +285,15 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
// 2.5 重置模板权限
|
||||
var permissionCodes = NormalizeValues(templateOptions.Permissions);
|
||||
var existingPermissions = await context.RoleTemplatePermissions
|
||||
.Where(x => x.RoleTemplateId == existing.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
// 2.6 清空旧权限并保存
|
||||
context.RoleTemplatePermissions.RemoveRange(existingPermissions);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
// 2.7 去重后的权限编码
|
||||
var distinctPermissionCodes = permissionCodes.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
foreach (var permissionCode in distinctPermissionCodes)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user