feat(auth): replace TOTP with phone-first login

This commit is contained in:
2026-07-28 17:39:29 +08:00
parent e7d350ec3d
commit c7f9a4e3c9
43 changed files with 18386 additions and 882 deletions

View File

@@ -9,7 +9,7 @@ namespace Tiku.IntegrationTests.Api;
public sealed class RbacAuthorizationTests
{
[Fact]
public async Task TenantPolicy_RequiresCurrentMembershipPermissionAndMfa()
public async Task TenantPolicy_requires_current_membership_and_permission()
{
var tenantId = Guid.NewGuid();
var userId = Guid.NewGuid();
@@ -21,20 +21,15 @@ public sealed class RbacAuthorizationTests
var authorization = provider.GetRequiredService<IAuthorizationService>();
var allowed = await authorization.AuthorizeAsync(
Principal(userId, "tenant", tenantId, hasMfa: true),
null,
BackendPermissions.TenantRoleManage);
var missingMfa = await authorization.AuthorizeAsync(
Principal(userId, "tenant", tenantId, hasMfa: false),
Principal(userId, "tenant", tenantId),
null,
BackendPermissions.TenantRoleManage);
var wrongTenant = await authorization.AuthorizeAsync(
Principal(userId, "tenant", Guid.NewGuid(), hasMfa: true),
Principal(userId, "tenant", Guid.NewGuid()),
null,
BackendPermissions.TenantRoleManage);
Assert.True(allowed.Succeeded);
Assert.False(missingMfa.Succeeded);
Assert.False(wrongTenant.Succeeded);
}
@@ -51,11 +46,11 @@ public sealed class RbacAuthorizationTests
var authorization = provider.GetRequiredService<IAuthorizationService>();
var tenantRealm = await authorization.AuthorizeAsync(
Principal(userId, "tenant", tenantId, hasMfa: true),
Principal(userId, "tenant", tenantId),
null,
BackendPermissions.PlatformRoleManage);
var platformRealm = await authorization.AuthorizeAsync(
Principal(userId, "platform", null, hasMfa: true),
Principal(userId, "platform", null),
null,
BackendPermissions.PlatformRoleManage);
@@ -71,7 +66,7 @@ public sealed class RbacAuthorizationTests
var snapshot = Snapshot(userId, tenantId);
await using var provider = Services(snapshot);
var authorization = provider.GetRequiredService<IAuthorizationService>();
var principal = Principal(userId, "tenant", tenantId, hasMfa: true);
var principal = Principal(userId, "tenant", tenantId);
((ClaimsIdentity)principal.Identity!).AddClaim(new Claim(ClaimTypes.Role, "TenantOwner"));
var result = await authorization.AuthorizeAsync(
@@ -87,7 +82,7 @@ public sealed class RbacAuthorizationTests
{
var tenantId = Guid.NewGuid();
var userId = Guid.NewGuid();
var principal = Principal(userId, "tenant", tenantId, hasMfa: true);
var principal = Principal(userId, "tenant", tenantId);
var selfSnapshot = Snapshot(
userId,
tenantId,
@@ -128,7 +123,7 @@ public sealed class RbacAuthorizationTests
true);
await using var provider = Services(Snapshot(userId, tenantId, dataScope: scope));
var authorization = provider.GetRequiredService<IAuthorizationService>();
var principal = Principal(userId, "tenant", tenantId, hasMfa: true);
var principal = Principal(userId, "tenant", tenantId);
var requirement = new TenantResourceAccessRequirement();
var own = await authorization.AuthorizeAsync(
@@ -168,7 +163,7 @@ public sealed class RbacAuthorizationTests
await using var tenantProvider = Services(tenantSnapshot);
var tenantAuthorization = tenantProvider.GetRequiredService<IAuthorizationService>();
var tenantAllowed = await tenantAuthorization.AuthorizeAsync(
Principal(userId, "tenant", tenantId, hasMfa: true),
Principal(userId, "tenant", tenantId),
null,
TikuPolicies.TenantBackofficeBootstrap);
@@ -179,11 +174,11 @@ public sealed class RbacAuthorizationTests
await using var platformProvider = Services(platformSnapshot);
var platformAuthorization = platformProvider.GetRequiredService<IAuthorizationService>();
var platformAllowed = await platformAuthorization.AuthorizeAsync(
Principal(userId, "platform", null, hasMfa: true),
Principal(userId, "platform", null),
null,
TikuPolicies.PlatformBackofficeBootstrap);
var tenantRealmDenied = await platformAuthorization.AuthorizeAsync(
Principal(userId, "tenant", tenantId, hasMfa: true),
Principal(userId, "tenant", tenantId),
null,
TikuPolicies.PlatformBackofficeBootstrap);
@@ -204,8 +199,7 @@ public sealed class RbacAuthorizationTests
private static ClaimsPrincipal Principal(
Guid userId,
string realm,
Guid? tenantId,
bool hasMfa)
Guid? tenantId)
{
var claims = new List<Claim>
{
@@ -217,11 +211,6 @@ public sealed class RbacAuthorizationTests
claims.Add(new Claim(TikuClaimTypes.TenantId, tenantId.Value.ToString()));
}
if (hasMfa)
{
claims.Add(new Claim(TikuClaimTypes.Mfa, "totp"));
}
return new ClaimsPrincipal(new ClaimsIdentity(claims, "test"));
}