forked from gongxuegit/tiku-backend.net
feat: harden SaaS authentication and authorization
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Tiku.Application.Auth;
|
||||
using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.Api.Contracts;
|
||||
|
||||
@@ -9,6 +10,8 @@ namespace Tiku.Api.Contracts;
|
||||
/// </summary>
|
||||
public sealed class PasswordLoginDto
|
||||
{
|
||||
[Required]
|
||||
public AuthRealm? Realm { get; set; }
|
||||
/// <summary>
|
||||
/// 平台控制域名登录时使用的租户代码;自定义域名登录可省略。
|
||||
/// </summary>
|
||||
@@ -17,18 +20,21 @@ public sealed class PasswordLoginDto
|
||||
public string? TenantCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号,建议前端提交规范化后的中国大陆手机号。
|
||||
/// 账号标识。tenant 可使用手机号,platform 可使用邮箱或用户名。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(320)]
|
||||
[Description("账号标识。tenant 可使用手机号,platform 可使用邮箱或用户名。")]
|
||||
public string? Identifier { get; set; }
|
||||
|
||||
[StringLength(32)]
|
||||
[Description("手机号,建议前端提交规范化后的中国大陆手机号。")]
|
||||
public string Phone { get; set; } = string.Empty;
|
||||
[Description("兼容手机号字段;新客户端应使用 identifier。")]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户密码。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(128, MinimumLength = 6)]
|
||||
[StringLength(128, MinimumLength = 10)]
|
||||
[Description("用户密码。")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -38,6 +44,8 @@ public sealed class PasswordLoginDto
|
||||
/// </summary>
|
||||
public sealed class SmsLoginDto
|
||||
{
|
||||
[Required]
|
||||
public AuthRealm? Realm { get; set; }
|
||||
/// <summary>
|
||||
/// 平台控制域名登录时使用的租户代码;自定义域名登录可省略。
|
||||
/// </summary>
|
||||
@@ -62,11 +70,29 @@ public sealed class SmsLoginDto
|
||||
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;
|
||||
|
||||
[StringLength(256)]
|
||||
public string? DeviceId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OAuth code 登录请求。
|
||||
/// </summary>
|
||||
public sealed class OAuthCodeDto
|
||||
{
|
||||
[Required]
|
||||
public AuthRealm? Realm { get; set; }
|
||||
/// <summary>
|
||||
/// 平台控制域名登录时使用的租户代码;自定义域名登录可省略。
|
||||
/// </summary>
|
||||
@@ -135,10 +161,12 @@ public sealed class AuthenticatedUserDto
|
||||
/// </summary>
|
||||
public string? Name { get; init; }
|
||||
|
||||
public AuthRealm Realm { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前登录租户成员摘要。
|
||||
/// </summary>
|
||||
public TenantMembershipSummary Tenant { get; init; } = default!;
|
||||
public TenantMembershipSummary? Tenant { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// access token 和 refresh token。
|
||||
@@ -153,8 +181,52 @@ public sealed class AuthenticatedUserDto
|
||||
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 MfaChallengeDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(2048)]
|
||||
public string ChallengeToken { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(64)]
|
||||
public string? Code { get; set; }
|
||||
}
|
||||
|
||||
public sealed class MfaConfirmDto
|
||||
{
|
||||
public AuthenticationResultDto Authentication { get; init; } = default!;
|
||||
public IReadOnlyList<string> RecoveryCodes { get; init; } = [];
|
||||
}
|
||||
|
||||
public sealed class RequiredPasswordChangeDto
|
||||
{
|
||||
[Required]
|
||||
[StringLength(2048)]
|
||||
public string ChallengeToken { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[StringLength(128, MinimumLength = 10)]
|
||||
public string NewPassword { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user