using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using TakeoutSaaS.Infrastructure.Identity.Options; using DomainIdentityUser = TakeoutSaaS.Domain.Identity.Entities.IdentityUser; namespace TakeoutSaaS.Infrastructure.Identity.Persistence; /// /// 后台账号初始化种子任务 /// public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger logger) : IHostedService { public async Task StartAsync(CancellationToken cancellationToken) { using var scope = serviceProvider.CreateScope(); var context = scope.ServiceProvider.GetRequiredService(); var options = scope.ServiceProvider.GetRequiredService>().Value; var passwordHasher = scope.ServiceProvider.GetRequiredService>(); await context.Database.MigrateAsync(cancellationToken); if (options.Users is null or { Count: 0 }) { logger.LogInformation("AdminSeed 未配置账号,跳过后台账号初始化"); return; } foreach (var userOptions in options.Users) { 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) { user = new DomainIdentityUser { Id = Guid.NewGuid(), Account = userOptions.Account, DisplayName = userOptions.DisplayName, TenantId = userOptions.TenantId, MerchantId = userOptions.MerchantId, Avatar = null, Roles = roles, Permissions = permissions, }; user.PasswordHash = passwordHasher.HashPassword(user, userOptions.Password); context.IdentityUsers.Add(user); logger.LogInformation("已创建后台账号 {Account}", user.Account); } else { user.DisplayName = userOptions.DisplayName; user.TenantId = userOptions.TenantId; user.MerchantId = userOptions.MerchantId; user.Roles = roles; user.Permissions = permissions; user.PasswordHash = passwordHasher.HashPassword(user, userOptions.Password); logger.LogInformation("已更新后台账号 {Account}", user.Account); } } await context.SaveChangesAsync(cancellationToken); } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; private static string[] NormalizeValues(string[]? values) => values == null ? [] : [.. values .Where(v => !string.IsNullOrWhiteSpace(v)) .Select(v => v.Trim()) .Distinct(StringComparer.OrdinalIgnoreCase)]; }