如何删除AppFixture中的cookies

问题描述 投票:0回答:1

我正在使用 FastEndpoints 和 cookie 身份验证来实现我的 REST API。为此,我有一个专门的登录端点:

await HttpContext.SignInAsync(await HttpContext.GetCookieAuthenticationSchemeAsync(), CreatePrincipal(), new AuthenticationProperties());

当从 Swagger 或基于 FastEndpoint 的

AppFixture
的集成测试调用时,效果很好。显然,客户端会自动从端点获取 cookie 并在必要时添加它们。

现在,我想创建一个注销。

与登录并行,我正在使用这种方法:

if (User.Identity?.IsAuthenticated == true)
{
   await httpContext.SignOutAsync();
}

这在 Swagger 中有效,但在测试中无效。我想也许 cookie 没有正确发送,所以我添加了

var siteCookies = HttpContext.Request.Cookies;
foreach (var cookie in siteCookies)
{
    httpContext.Response.Cookies.Delete(cookie.Key);

    // OR

    var opts = new CookieOptions();
    opts.Expires = DateTimeOffset.MinValue;
    httpContext.Response.Cookies.Append(cookie.Key, string.Empty, opts);
}

我可以看到正确的 cookie 被标记为已删除,但

AppFixture
不会识别它。所以我把它改为:

public class MyApiFixture : AppFixture<Program>
{
    public void CreateMyClient()
    {
        var options = new ClientOptions
        {
            HandleCookies = false, // we handle cookies 🍪
        };
        options.AddHandlers(new CookieContainerHandler(CookieJar));
        Client = CreateClient(options);
    }

    public CookieContainer CookieJar { get; } = new();

    public void UpdateCookies(HttpResponseMessage response)
    {
        if (!response.Headers.Contains("Set-Cookie")) return;
 
        var uri = new Uri("http://localhost");;
        foreach (var cookieHeader in response.Headers.GetValues("Set-Cookie"))
        {
            CookieJar.SetCookies(uri, cookieHeader);
        }
    }
}

我将注销端点的结果放入

UpdateCookies()
,但很明显,cookie 是自动应用的(因此根据使用的方法被删除或过期)。尽管如此,最后一个有效的 cookie 仍会再次发送。

如何让 FastEndpoint 的

AppFixture
以与添加 Cookie 相同的方式应用已删除的 Cookie?

c# asp.net-core fast-endpoints
1个回答
0
投票

我尝试使用简化的端点来复制您的初始问题,如下所示:

sealed class LoginEndpoint : EndpointWithoutRequest<string>
{
    public override void Configure()
    {
        Post("login");
        AllowAnonymous();
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await CookieAuth.SignInAsync(_ => { });
        await SendAsync("You are signed in!");
    }
}

sealed class ProtectedEndpoint : EndpointWithoutRequest
{
    public override void Configure()
    {
        Get("protected");
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await SendAsync("You are authenticated!");
    }
}

sealed class LogoutEndpoint : EndpointWithoutRequest
{
    public override void Configure()
    {
        Get("logout");
    }

    public override async Task HandleAsync(CancellationToken c)
    {
        await CookieAuth.SignOutAsync();
        await SendAsync("You are signed out!");
    }
}

和这样的启动配置:

var bld = WebApplication.CreateBuilder(args);
bld.Services
   .AddAuthenticationCookie(validFor: TimeSpan.FromMinutes(10))
   .AddAuthorization()
   .AddFastEndpoints()
   .SwaggerDocument(o => o.EnableJWTBearerAuth = false);

var app = bld.Build();
app.UseAuthentication()
   .UseAuthorization()
   .UseFastEndpoints()
   .UseSwaggerGen();
app.Run();

然后我创建了一些像这样的有序测试来验证注销是否有效,并且测试

HttpClient
尊重注销。

public class CookieTests(App App) : TestBase<App>
{
    [Fact, Priority(1)]
    public async Task Unauthenticated_User_Receives_401_Unauthorized()
    {
        var (rsp, _) = await App.Client.GETAsync<ProtectedEndpoint, EmptyResponse>();
        rsp.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
    }

    [Fact, Priority(2)]
    public async Task Authenticated_User_Can_Access_Protected_Endpoint()
    {
        var (rsp1, res1) = await App.Client.POSTAsync<LoginEndpoint, string>();
        rsp1.IsSuccessStatusCode.Should().BeTrue();
        res1.Should().Be("You are signed in!");

        var (rsp2, res2) = await App.Client.GETAsync<ProtectedEndpoint, string>();
        rsp2.IsSuccessStatusCode.Should().BeTrue();
        res2.Should().Be("You are authenticated!");
    }

    [Fact, Priority(3)]
    public async Task Authenticated_User_Receives_401_After_Singing_Out()
    {
        var (rsp1, res1) = await App.Client.GETAsync<ProtectedEndpoint, string>();
        rsp1.IsSuccessStatusCode.Should().BeTrue();
        res1.Should().Be("You are authenticated!");

        var (rsp2, res2) = await App.Client.GETAsync<LogoutEndpoint, string>();
        rsp2.IsSuccessStatusCode.Should().BeTrue();
        res2.Should().Be("You are signed out!");

        var (rsp3, _) = await App.Client.GETAsync<ProtectedEndpoint, EmptyResponse>();
        rsp3.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
    }
}

所有测试均顺利通过。您可以通过下载重现项目来亲自查看从这里

如果您希望我进一步查看此问题,请更新重现项目以突出显示问题并将其上传到某处,以便我进行调查。

© www.soinside.com 2019 - 2024. All rights reserved.