Files
MoShiro/backend/tests/MoShiro.Backend.Tests/LoginRateLimitTests.cs
T
justme 83e5120377 refactor!: rename the project from Monitor to MoShiro
Namespaces, assemblies, projects and directories, the solution, binaries,
images, systemd units, config paths, environment variables, protocol method
names, the media type and the raw chunk magic all move to MoShiro/moshiro.
Existing data and deployments are not compatible and must be recreated.
Also fix the architecture tests after the solution layout change and make
the update tests independent of their order.
2026-10-07 01:49:04 +08:00

50 lines
2.1 KiB
C#

using System.Net;
using System.Text.Json.Nodes;
namespace MoShiro.Backend.Tests;
/// <summary>登录限流按来源地址计,会影响同一地址上的其他登录,所以用独立的后端实例。</summary>
public sealed class LoginRateLimitTests : IClassFixture<StrictLoginFixture>
{
private readonly StrictLoginFixture _backend;
public LoginRateLimitTests(StrictLoginFixture backend)
{
_backend = backend;
}
[Fact]
public async Task LoginAttempts_AreRateLimited_WithRetryAfter_AndASuccessfulLoginIsAlsoCounted()
{
using HttpClient client = _backend.NewClient();
HttpResponseMessage? limited = null;
int attempts = 0;
for (; attempts < 15 && limited is null; attempts++)
{
HttpResponseMessage response = await client.PostAsync("/api/admin/auth/login", BackendFixture.Json(new JsonObject { ["username"] = "admin", ["password"] = "wrong" }));
if (response.StatusCode == HttpStatusCode.TooManyRequests)
{
limited = response;
}
else
{
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
response.Dispose();
}
}
Assert.NotNull(limited);
using (limited)
{
// 前一次登录(创建管理员令牌)也占了一次配额:第 10 次之内的都是 401
Assert.InRange(attempts, 9, 10);
Assert.Equal("too_many_requests", JsonNode.Parse(await limited.Content.ReadAsStringAsync())!["code"]!.GetValue<string>());
Assert.True(limited.Headers.RetryAfter!.Delta!.Value.TotalSeconds is >= 1 and <= 60);
}
// 被限流的来源连正确的密码也不行:限流发生在校验密码之前,不能被用来猜密码
using HttpResponseMessage correct = await client.PostAsync("/api/admin/auth/login", BackendFixture.Json(new JsonObject { ["username"] = BackendFixture.AdminUser, ["password"] = BackendFixture.AdminPassword }));
Assert.Equal(HttpStatusCode.TooManyRequests, correct.StatusCode);
}
}