登录验证码接入
This commit is contained in:
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,
|
||||
|
||||
Reference in new issue
Block a user