diff --git a/TakeoutSaaS.Docs b/TakeoutSaaS.Docs
index e962798..2f508d7 160000
--- a/TakeoutSaaS.Docs
+++ b/TakeoutSaaS.Docs
@@ -1 +1 @@
-Subproject commit e962798f4637273d519d60053304425c9733e823
+Subproject commit 2f508d7b52f849b14e98fd0a7e564edc35a5b684
diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/AuthController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/AuthController.cs
index b68236f..9efd7c4 100644
--- a/src/Api/TakeoutSaaS.AdminApi/Controllers/AuthController.cs
+++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/AuthController.cs
@@ -23,7 +23,7 @@ namespace TakeoutSaaS.AdminApi.Controllers;
public sealed class AuthController(IAdminAuthService authService, IMediator mediator) : BaseApiController
{
///
- /// 登录获取 Token
+ /// 账号名+手机号登录获取 Token
///
/// 登录请求。
/// 取消标记。
@@ -37,22 +37,6 @@ public sealed class AuthController(IAdminAuthService authService, IMediator medi
return ApiResponse.Ok(response);
}
- ///
- /// 免租户号登录(仅账号+密码)。
- ///
- /// 登录请求。
- /// 取消标记。
- /// 包含访问令牌与刷新令牌的响应。
- /// 用于前端简化登录,无需额外传递租户号。
- [HttpPost("login/simple")]
- [AllowAnonymous]
- [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
- public async Task> LoginSimple([FromBody] AdminLoginRequest request, CancellationToken cancellationToken)
- {
- var response = await authService.LoginSimpleAsync(request, cancellationToken);
- return ApiResponse.Ok(response);
- }
-
///
/// 刷新 Token
///
diff --git a/src/Application/TakeoutSaaS.Application/Identity/Abstractions/IAdminAuthService.cs b/src/Application/TakeoutSaaS.Application/Identity/Abstractions/IAdminAuthService.cs
index ee6935c..6e00acc 100644
--- a/src/Application/TakeoutSaaS.Application/Identity/Abstractions/IAdminAuthService.cs
+++ b/src/Application/TakeoutSaaS.Application/Identity/Abstractions/IAdminAuthService.cs
@@ -12,11 +12,6 @@ public interface IAdminAuthService
///
Task LoginAsync(AdminLoginRequest request, CancellationToken cancellationToken = default);
- ///
- /// 简化登录:与标准登录一致(Admin Portal)。
- ///
- Task LoginSimpleAsync(AdminLoginRequest request, CancellationToken cancellationToken = default);
-
///
/// 刷新 Token。
///
diff --git a/src/Application/TakeoutSaaS.Application/Identity/Contracts/AdminLoginRequest.cs b/src/Application/TakeoutSaaS.Application/Identity/Contracts/AdminLoginRequest.cs
index 865e263..4321e0d 100644
--- a/src/Application/TakeoutSaaS.Application/Identity/Contracts/AdminLoginRequest.cs
+++ b/src/Application/TakeoutSaaS.Application/Identity/Contracts/AdminLoginRequest.cs
@@ -5,19 +5,26 @@ namespace TakeoutSaaS.Application.Identity.Contracts;
///
/// 管理后台登录请求。
///
-public sealed class AdminLoginRequest
+public sealed record AdminLoginRequest
{
///
- /// 账号。
+ /// 账号名。
///
[Required]
[MaxLength(64)]
- public string Account { get; set; } = string.Empty;
+ public string AccountName { get; init; } = string.Empty;
+
+ ///
+ /// 手机号。
+ ///
+ [Required]
+ [MaxLength(32)]
+ public string Phone { get; init; } = string.Empty;
///
/// 密码。
///
[Required]
[MaxLength(128)]
- public string Password { get; set; } = string.Empty;
+ public string Password { get; init; } = string.Empty;
}
diff --git a/src/Application/TakeoutSaaS.Application/Identity/Services/AdminAuthService.cs b/src/Application/TakeoutSaaS.Application/Identity/Services/AdminAuthService.cs
index 24c9302..b3b9dca 100644
--- a/src/Application/TakeoutSaaS.Application/Identity/Services/AdminAuthService.cs
+++ b/src/Application/TakeoutSaaS.Application/Identity/Services/AdminAuthService.cs
@@ -32,11 +32,28 @@ public sealed class AdminAuthService(
/// 账号或密码错误时抛出
public async Task LoginAsync(AdminLoginRequest request, CancellationToken cancellationToken = default)
{
- // 1. 根据账号查找用户
- var user = await userRepository.FindByAccountAsync(PortalType.Admin, null, request.Account, cancellationToken)
- ?? throw new BusinessException(ErrorCodes.Unauthorized, "账号或密码错误");
+ // 1. 标准化输入
+ var accountName = request.AccountName?.Trim() ?? string.Empty;
+ var phone = request.Phone?.Trim() ?? string.Empty;
+ var password = request.Password;
- // 2. 校验账号状态
+ // 2. (空行后) 参数校验
+ if (string.IsNullOrWhiteSpace(accountName) || string.IsNullOrWhiteSpace(phone) || string.IsNullOrWhiteSpace(password))
+ {
+ throw new BusinessException(ErrorCodes.BadRequest, "账号名、手机号与密码不能为空");
+ }
+
+ // 3. (空行后) 根据账号查找用户
+ var user = await userRepository.FindByAccountAsync(PortalType.Admin, null, accountName, cancellationToken)
+ ?? throw new BusinessException(ErrorCodes.Unauthorized, "账号名、手机号或密码错误");
+
+ // 4. (空行后) 校验手机号匹配
+ if (!string.Equals(user.Phone?.Trim(), phone, StringComparison.Ordinal))
+ {
+ throw new BusinessException(ErrorCodes.Unauthorized, "账号名、手机号或密码错误");
+ }
+
+ // 5. (空行后) 校验账号状态
var now = DateTime.UtcNow;
if (user.Status == IdentityUserStatus.Disabled)
{
@@ -58,43 +75,22 @@ public sealed class AdminAuthService(
throw new BusinessException(ErrorCodes.Forbidden, "账号需要重置密码,请通过重置链接设置新密码");
}
- // 3. 验证密码(使用 ASP.NET Core Identity 的密码哈希器)
- var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, request.Password);
+ // 6. (空行后) 验证密码(使用 ASP.NET Core Identity 的密码哈希器)
+ var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password);
if (result == PasswordVerificationResult.Failed)
{
await IncreaseFailedLoginAsync(user.Id, now, cancellationToken);
- throw new BusinessException(ErrorCodes.Unauthorized, "账号或密码错误");
+ throw new BusinessException(ErrorCodes.Unauthorized, "账号名、手机号或密码错误");
}
- // 4. 更新登录成功状态
+ // 7. (空行后) 更新登录成功状态
await UpdateLoginSuccessAsync(user.Id, now, cancellationToken);
- // 5. 构建用户档案并生成令牌
+ // 8. (空行后) 构建用户档案并生成令牌
var profile = await BuildProfileAsync(user, cancellationToken);
return await jwtTokenService.CreateTokensAsync(profile, false, cancellationToken);
}
- ///
- /// 简化登录:与标准登录一致(Admin Portal)。
- ///
- /// 登录请求
- /// 取消令牌
- /// 令牌响应
- public async Task LoginSimpleAsync(AdminLoginRequest request, CancellationToken cancellationToken = default)
- {
- // 1. 参数校验
- if (string.IsNullOrWhiteSpace(request.Account))
- {
- throw new BusinessException(ErrorCodes.BadRequest, "账号不能为空");
- }
-
- // 2. (空行后) 标准化账号
- request.Account = request.Account.Trim();
-
- // 3. (空行后) 走标准登录逻辑(Admin Portal)
- return await LoginAsync(request, cancellationToken);
- }
-
///
/// 刷新访问令牌:使用刷新令牌获取新的访问令牌和刷新令牌。
///