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

@@ -22,9 +22,7 @@ public sealed class AuthRateLimitPolicyTests
[$"{AuthRateLimitOptions.SectionName}:PasswordPermitLimit"] = "7",
[$"{AuthRateLimitOptions.SectionName}:PasswordWindowSeconds"] = "600",
[$"{AuthRateLimitOptions.SectionName}:SmsPermitLimit"] = "3",
[$"{AuthRateLimitOptions.SectionName}:SmsWindowSeconds"] = "90",
[$"{AuthRateLimitOptions.SectionName}:MfaPermitLimit"] = "4",
[$"{AuthRateLimitOptions.SectionName}:MfaWindowSeconds"] = "120"
[$"{AuthRateLimitOptions.SectionName}:SmsWindowSeconds"] = "90"
})
.Build();
@@ -37,8 +35,6 @@ public sealed class AuthRateLimitPolicyTests
Assert.Equal(600, options.PasswordWindowSeconds);
Assert.Equal(3, options.SmsPermitLimit);
Assert.Equal(90, options.SmsWindowSeconds);
Assert.Equal(4, options.MfaPermitLimit);
Assert.Equal(120, options.MfaWindowSeconds);
}
[Fact]
@@ -47,7 +43,7 @@ public sealed class AuthRateLimitPolicyTests
var options = new AuthRateLimitOptions
{
PasswordPermitLimit = 0,
MfaWindowSeconds = 0
SmsWindowSeconds = 0
};
var validationResults = new List<ValidationResult>();
@@ -73,13 +69,10 @@ public sealed class AuthRateLimitPolicyTests
AssertPolicy(nameof(AuthController.SendSmsCode), AuthRateLimitPolicies.Sms);
}
[Theory]
[InlineData(nameof(AuthController.SetupTotp))]
[InlineData(nameof(AuthController.ConfirmTotp))]
[InlineData(nameof(AuthController.VerifyTotp))]
public void Mfa_challenge_endpoints_use_the_mfa_named_policy(string methodName)
[Fact]
public void Required_password_change_uses_the_password_named_policy()
{
AssertPolicy(methodName, AuthRateLimitPolicies.Mfa);
AssertPolicy(nameof(AuthController.ChangeRequiredPassword), AuthRateLimitPolicies.Password);
}
[Fact]
@@ -130,23 +123,6 @@ public sealed class AuthRateLimitPolicyTests
Assert.DoesNotContain("13800000000", first, StringComparison.Ordinal);
}
[Fact]
public async Task Mfa_partition_uses_the_challenge_token_and_resets_the_request_body()
{
const string body = """{"challengeToken":"challenge-one","code":"123456"}""";
var first = await CapturePartitionAsync(
AuthRateLimitPolicies.Mfa,
body,
"127.0.0.1");
var second = await CapturePartitionAsync(
AuthRateLimitPolicies.Mfa,
"""{"challengeToken":"challenge-two","code":"123456"}""",
"127.0.0.1");
Assert.NotEqual(first, second);
Assert.DoesNotContain("challenge-one", first, StringComparison.Ordinal);
}
private static void AssertPolicy(string methodName, string expectedPolicy)
{
var method = typeof(AuthController).GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);