登录验证码接入

This commit is contained in:
biss committed 2026-09-11 22:05:07 +08:00
1 parent ae075bda6d
commit f489a3553c
15 files changed
+471 -19

No files matched your search

@@ -109,6 +109,8 @@ public sealed class AuthControllerTests
userManager,
new StubAuthSessionService(),
new TwoFactorLoginTicketService(new Microsoft.AspNetCore.DataProtection.EphemeralDataProtectionProvider()),
new LoginCaptchaService(new Microsoft.Extensions.Caching.Distributed.MemoryDistributedCache(
Microsoft.Extensions.Options.Options.Create(new Microsoft.Extensions.Caching.Memory.MemoryDistributedCacheOptions()))),
NoOpAppCache.Instance);
var request = new StudentActivationRequest(
student.Name,
@@ -0,0 +1,61 @@
using System.Text;
using System.Text.RegularExpressions;
using Jiaowu.Api.Infrastructure.Auth;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
namespace Jiaowu.Api.Tests;
public sealed class LoginCaptchaServiceTests
{
[Fact]
public async Task Text_challenge_creates_a_one_time_proof_bound_to_the_same_device()
{
var cache = new MemoryDistributedCache(
Options.Create(new MemoryDistributedCacheOptions()));
var service = new LoginCaptchaService(cache);
var context = CreateContext("127.0.0.1");
LoginCaptchaChallenge challenge;
do
{
challenge = await service.CreateAsync("device-hash", context, CancellationToken.None);
} while (challenge.Kind != nameof(LoginCaptchaKind.Text));
var svg = Encoding.UTF8.GetString(Convert.FromBase64String(challenge.ImageSvg.Split(',')[1]));
var text = Regex.Match(svg, "fill='#1f456c'>([A-Z0-9]+)</text>").Groups[1].Value;
var proof = await service.VerifyAsync(
new LoginCaptchaVerification(challenge.Id, "device-hash", text, null, null),
context,
CancellationToken.None);
Assert.NotNull(proof);
Assert.True(await service.ConsumeProofAsync(proof!, "device-hash", context, CancellationToken.None));
Assert.False(await service.ConsumeProofAsync(proof!, "device-hash", context, CancellationToken.None));
}
[Fact]
public async Task Challenge_cannot_be_verified_from_a_different_device_binding()
{
var cache = new MemoryDistributedCache(
Options.Create(new MemoryDistributedCacheOptions()));
var service = new LoginCaptchaService(cache);
var context = CreateContext("127.0.0.1");
var challenge = await service.CreateAsync("device-a", context, CancellationToken.None);
var proof = await service.VerifyAsync(
new LoginCaptchaVerification(challenge.Id, "device-b", null, 0, []),
context,
CancellationToken.None);
Assert.Null(proof);
}
private static DefaultHttpContext CreateContext(string ip)
{
var context = new DefaultHttpContext();
context.Connection.RemoteIpAddress = System.Net.IPAddress.Parse(ip);
return context;
}
}
@@ -187,6 +187,7 @@ public sealed class SsoControllerTests
userManager,
new StubAuthSessionService(),
cache,
new LoginCaptchaService(cache),
Options.Create(new SsoOptions
{
Enabled = true,