feat: 支持租户伪装登录与管理员重置链接
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TakeoutSaaS.Application.Identity.Abstractions;
|
||||
using TakeoutSaaS.Application.Identity.Commands;
|
||||
using TakeoutSaaS.Application.Identity.Contracts;
|
||||
using TakeoutSaaS.Module.Authorization.Attributes;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
@@ -14,10 +16,11 @@ namespace TakeoutSaaS.AdminApi.Controllers;
|
||||
/// </summary>
|
||||
/// <remarks>提供登录、刷新 Token 以及用户权限查询能力。</remarks>
|
||||
/// <param name="authService">认证服务</param>
|
||||
/// <param name="mediator">中介者。</param>
|
||||
[ApiVersion("1.0")]
|
||||
[Authorize]
|
||||
[Route("api/admin/v{version:apiVersion}/auth")]
|
||||
public sealed class AuthController(IAdminAuthService authService) : BaseApiController
|
||||
public sealed class AuthController(IAdminAuthService authService, IMediator mediator) : BaseApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录获取 Token
|
||||
@@ -65,6 +68,26 @@ public sealed class AuthController(IAdminAuthService authService) : BaseApiContr
|
||||
return ApiResponse<TokenResponse>.Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过重置链接令牌重置管理员密码。
|
||||
/// </summary>
|
||||
/// <remarks>令牌为一次性使用;成功后即可使用新密码登录。</remarks>
|
||||
[HttpPost("reset-password")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<object>> ResetPassword([FromBody] ResetAdminPasswordRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 通过令牌重置密码
|
||||
await mediator.Send(new ResetAdminPasswordByTokenCommand
|
||||
{
|
||||
Token = request.Token,
|
||||
NewPassword = request.NewPassword
|
||||
}, cancellationToken);
|
||||
|
||||
// 2. 返回成功
|
||||
return ApiResponse.Success("密码重置成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前用户信息
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using TakeoutSaaS.Application.App.Tenants.Commands;
|
||||
using TakeoutSaaS.Application.App.Tenants.Dto;
|
||||
using TakeoutSaaS.Application.App.Tenants.Queries;
|
||||
using TakeoutSaaS.Application.Identity.Contracts;
|
||||
using TakeoutSaaS.Module.Authorization.Attributes;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
using TakeoutSaaS.Shared.Web.Api;
|
||||
@@ -318,6 +319,49 @@ public sealed class TenantsController(IMediator mediator) : BaseApiController
|
||||
return ApiResponse<PagedResult<TenantAuditLogDto>>.Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 伪装登录租户(仅平台超级管理员可用)。
|
||||
/// </summary>
|
||||
/// <returns>目标租户主管理员的令牌对。</returns>
|
||||
[HttpPost("{tenantId:long}/impersonate")]
|
||||
[PermissionAuthorize("tenant:read")]
|
||||
[ProducesResponseType(typeof(ApiResponse<TokenResponse>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<TokenResponse>> Impersonate(long tenantId, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 执行伪装登录
|
||||
var result = await mediator.Send(new ImpersonateTenantCommand { TenantId = tenantId }, cancellationToken);
|
||||
|
||||
// 2. 返回令牌
|
||||
return ApiResponse<TokenResponse>.Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成租户主管理员重置密码链接(仅平台超级管理员可用)。
|
||||
/// </summary>
|
||||
/// <remarks>链接默认 24 小时有效且仅可使用一次。</remarks>
|
||||
/// <returns>重置密码链接。</returns>
|
||||
[HttpPost("{tenantId:long}/admin/reset-link")]
|
||||
[PermissionAuthorize("tenant:read")]
|
||||
[ProducesResponseType(typeof(ApiResponse<string>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<string>> CreateAdminResetLink(long tenantId, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 生成一次性令牌
|
||||
var token = await mediator.Send(new CreateTenantAdminResetLinkTokenCommand { TenantId = tenantId }, cancellationToken);
|
||||
|
||||
// 2. (空行后) 解析前端来源(优先 Origin,避免拼成 AdminApi 域名)
|
||||
var origin = Request.Headers.Origin.ToString();
|
||||
if (string.IsNullOrWhiteSpace(origin))
|
||||
{
|
||||
origin = $"{Request.Scheme}://{Request.Host}";
|
||||
}
|
||||
|
||||
origin = origin.TrimEnd('/');
|
||||
var resetUrl = $"{origin}/#/auth/reset-password?token={Uri.EscapeDataString(token)}";
|
||||
|
||||
// 3. (空行后) 返回链接
|
||||
return ApiResponse<string>.Ok(resetUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配额校验并占用额度(门店/账号/短信/配送)。
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user