using System.ComponentModel; using System.ComponentModel.DataAnnotations; using Tiku.Application.Auth; using Tiku.Domain.Tenancy; namespace Tiku.Api.Contracts; /// /// PasswordLogin请求 DTO。 /// public sealed class PasswordLoginDto { /// /// 认证域。 /// [Required] public AuthRealm? Realm { get; set; } /// /// 租户编码。 /// [StringLength(100)] [Description("平台控制域名登录时使用的租户代码;自定义域名登录可省略。")] public string? TenantCode { get; set; } /// /// 账号标识。 /// [StringLength(320)] [Description("账号标识。tenant 可使用手机号,platform 可使用邮箱或用户名。")] public string? Identifier { get; set; } /// /// 兼容手机号字段;新客户端应使用 identifier。 /// [StringLength(32)] [Description("兼容手机号字段;新客户端应使用 identifier。")] public string? Phone { get; set; } /// /// 密码。 /// [Required] [StringLength(128, MinimumLength = 8)] [Description("用户密码。")] public string Password { get; set; } = string.Empty; } /// /// SmsLogin请求 DTO。 /// public sealed class SmsLoginDto { /// /// 认证域。 /// [Required] public AuthRealm? Realm { get; set; } /// /// 租户编码。 /// [StringLength(100)] [Description("平台控制域名登录时使用的租户代码;自定义域名登录可省略。")] public string? TenantCode { get; set; } /// /// 手机号。 /// [Required] [StringLength(32)] [Description("中国大陆手机号。")] public string Phone { get; set; } = string.Empty; /// /// 编码。 /// [Required] [StringLength(12, MinimumLength = 4)] [Description("收到的短信验证码。")] public string Code { get; set; } = string.Empty; } /// /// 发送短信验证码请求。 /// public sealed class SendSmsCodeDto { /// /// 认证域。 /// [Required] public AuthRealm? Realm { get; set; } /// /// 租户编码。 /// [StringLength(100)] public string? TenantCode { get; set; } /// /// 手机号。 /// [Required] [StringLength(32)] public string Phone { get; set; } = string.Empty; /// /// 设备 ID。 /// [StringLength(256)] public string? DeviceId { get; set; } } /// /// O认证编码请求 DTO。 /// public sealed class OAuthCodeDto { /// /// 认证域。 /// [Required] public AuthRealm? Realm { get; set; } /// /// 租户编码。 /// [StringLength(100)] [Description("平台控制域名登录时使用的租户代码;自定义域名登录可省略。")] public string? TenantCode { get; set; } /// /// 编码。 /// [Required] [StringLength(512)] [Description("OAuth 平台返回的一次性授权 code。")] public string Code { get; set; } = string.Empty; /// /// 公开用户资料。 /// [Description("客户端可提供的公开用户资料,不允许包含 token/secret。当前后端先保留模板字段,后续按业务需要逐步使用。")] public Dictionary? Profile { get; set; } /// /// 语言。 /// [StringLength(20)] [Description("微信用户资料语言,例如 zh_CN。当前微信小程序登录不会使用该字段。")] public string? Lang { get; set; } } /// /// 刷新会话请求 DTO。 /// public sealed class RefreshSessionDto { /// /// 刷新令牌。 /// [Required] [StringLength(2048)] [Description("refresh token。服务端只存储哈希,明文只返回给客户端一次。")] public string RefreshToken { get; set; } = string.Empty; } /// /// Authenticated用户请求 DTO。 /// public sealed class AuthenticatedUserDto { /// /// 用户 ID。 /// public Guid UserId { get; init; } /// /// 手机号。 /// public string? Phone { get; init; } /// /// 邮箱。 /// public string? Email { get; init; } /// /// 名称。 /// public string? Name { get; init; } /// /// 认证域。 /// public AuthRealm Realm { get; init; } /// /// 租户成员摘要。 /// public TenantMembershipSummary? Tenant { get; init; } /// /// 访问令牌和刷新令牌。 /// public AuthTokenPair Tokens { get; init; } = default!; public static AuthenticatedUserDto FromApplication(AuthenticatedUser user) { return new AuthenticatedUserDto { UserId = user.UserId, Phone = user.Phone, Email = user.Email, Name = user.Name, Realm = user.Realm, Tenant = user.Tenant, Tokens = user.Tokens }; } } /// /// 登录认证结果。 /// public sealed class AuthenticationResultDto { /// /// 状态。 /// public AuthenticationStatus Status { get; init; } /// /// 用户信息。 /// public AuthenticatedUserDto? User { get; init; } /// /// 挑战令牌。 /// public string? ChallengeToken { get; init; } /// /// 挑战令牌过期时间。 /// public DateTimeOffset? ChallengeExpiresAt { get; init; } public static AuthenticationResultDto FromApplication(AuthenticationResult result) => new() { Status = result.Status, User = result.User is null ? null : AuthenticatedUserDto.FromApplication(result.User), ChallengeToken = result.ChallengeToken, ChallengeExpiresAt = result.ChallengeExpiresAt }; } /// /// 首次登录必改密码请求。 /// public sealed class RequiredPasswordChangeDto { /// /// 挑战令牌。 /// [Required] [StringLength(2048)] public string ChallengeToken { get; set; } = string.Empty; /// /// 新密码。 /// [Required] [StringLength(128, MinimumLength = 8)] public string NewPassword { get; set; } = string.Empty; }