fix: 自助注册回填主管理员

This commit is contained in:
2025-12-15 15:41:43 +08:00
parent 2150ae8f8c
commit 9d80f02bc5
3 changed files with 50 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
using MediatR;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
@@ -17,6 +18,8 @@ namespace TakeoutSaaS.Application.App.Tenants.Handlers;
public sealed class CreateTenantAdminResetLinkTokenCommandHandler(
ITenantRepository tenantRepository,
ITenantProvider tenantProvider,
ITenantContextAccessor tenantContextAccessor,
IIdentityUserRepository identityUserRepository,
ICurrentUserAccessor currentUserAccessor,
IAdminAuthService adminAuthService,
IAdminPasswordResetTokenStore tokenStore)
@@ -38,9 +41,28 @@ public sealed class CreateTenantAdminResetLinkTokenCommandHandler(
var tenant = await tenantRepository.FindByIdAsync(request.TenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
// 2.1 (空行后) 若缺少主管理员则自动回填(兼容历史数据)
if (!tenant.PrimaryOwnerUserId.HasValue || tenant.PrimaryOwnerUserId.Value == 0)
{
throw new BusinessException(ErrorCodes.BadRequest, "该租户未配置主管理员账号,无法生成重置链接");
var originalContextForFix = tenantContextAccessor.Current;
tenantContextAccessor.Current = new TenantContext(tenant.Id, tenant.Code, "admin:reset-link:fix-owner");
try
{
var users = await identityUserRepository.SearchAsync(tenant.Id, keyword: null, cancellationToken);
var ownerCandidate = users.OrderBy(x => x.CreatedAt).FirstOrDefault();
if (ownerCandidate == null)
{
throw new BusinessException(ErrorCodes.BadRequest, "该租户未配置主管理员账号,且未找到可用管理员账号");
}
tenant.PrimaryOwnerUserId = ownerCandidate.Id;
await tenantRepository.UpdateTenantAsync(tenant, cancellationToken);
await tenantRepository.SaveChangesAsync(cancellationToken);
}
finally
{
tenantContextAccessor.Current = originalContextForFix;
}
}
// 3. (空行后) 签发一次性重置令牌(默认 24 小时有效)
@@ -70,4 +92,3 @@ public sealed class CreateTenantAdminResetLinkTokenCommandHandler(
return token;
}
}

View File

@@ -2,6 +2,7 @@ using MediatR;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Application.Identity.Contracts;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
@@ -19,6 +20,7 @@ public sealed class ImpersonateTenantCommandHandler(
ITenantRepository tenantRepository,
ITenantProvider tenantProvider,
ITenantContextAccessor tenantContextAccessor,
IIdentityUserRepository identityUserRepository,
ICurrentUserAccessor currentUserAccessor,
IAdminAuthService adminAuthService,
IJwtTokenService jwtTokenService)
@@ -46,9 +48,28 @@ public sealed class ImpersonateTenantCommandHandler(
var tenant = await tenantRepository.FindByIdAsync(request.TenantId, cancellationToken)
?? throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
// 2.1 (空行后) 若缺少主管理员则自动回填(兼容历史数据)
if (!tenant.PrimaryOwnerUserId.HasValue || tenant.PrimaryOwnerUserId.Value == 0)
{
throw new BusinessException(ErrorCodes.BadRequest, "该租户未配置主管理员账号,无法伪装登录");
var originalContextForFix = tenantContextAccessor.Current;
tenantContextAccessor.Current = new TenantContext(tenant.Id, tenant.Code, "admin:impersonate:fix-owner");
try
{
var users = await identityUserRepository.SearchAsync(tenant.Id, keyword: null, cancellationToken);
var ownerCandidate = users.OrderBy(x => x.CreatedAt).FirstOrDefault();
if (ownerCandidate == null)
{
throw new BusinessException(ErrorCodes.BadRequest, "该租户未配置主管理员账号,且未找到可用管理员账号");
}
tenant.PrimaryOwnerUserId = ownerCandidate.Id;
await tenantRepository.UpdateTenantAsync(tenant, cancellationToken);
await tenantRepository.SaveChangesAsync(cancellationToken);
}
finally
{
tenantContextAccessor.Current = originalContextForFix;
}
}
// 3. (空行后) 进入目标租户上下文以读取租户内用户(避免多租户查询过滤导致找不到用户)

View File

@@ -95,6 +95,11 @@ public sealed class SelfRegisterTenantCommandHandler(
await identityUserRepository.AddAsync(adminUser, cancellationToken);
await identityUserRepository.SaveChangesAsync(cancellationToken);
// 7.1 (空行后) 回填主管理员标识,确保后续伪装登录/重置管理员等能力可用
tenant.PrimaryOwnerUserId = adminUser.Id;
await tenantRepository.UpdateTenantAsync(tenant, cancellationToken);
await tenantRepository.SaveChangesAsync(cancellationToken);
// 8. 初始化租户管理员角色模板
await mediator.Send(new InitializeRoleTemplatesCommand
{