feat(saas): implement marketplace and tenant onboarding

This commit is contained in:
2026-07-29 13:58:59 +08:00
parent 76606029e2
commit 6db200a2fc
145 changed files with 16862 additions and 94529 deletions

View File

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