You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FastEndpoints的AppFixture中正确删除Cookie?

解决FastEndpoints AppFixture中Cookie登出失效问题

问题背景

我用FastEndpoints结合Cookie认证开发REST API,登录逻辑如下,在Swagger和AppFixture集成测试里都能正常工作,客户端可自动处理Cookie:

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

但登出功能仅在Swagger中有效,AppFixture测试里完全失效:

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

尝试手动删除Cookie也没用,能看到Cookie被标记为删除,但AppFixture就是不识别:

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

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

后来自定义了MyApiFixture处理Cookie,虽然能看到登出后的删除/过期操作已应用,但测试时还是会发送之前的有效Cookie:

public class MyApiFixture : AppFixture<Program>
{
    public void CreateMyClient()
    {
        var options = new ClientOptions
        {
            HandleCookies = false, // 手动处理Cookie
        };
        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);
        }
    }
}

核心原因

CookieContainer处理Set-Cookie头的删除/过期指令时,要求完全匹配原始Cookie的所有属性(比如Path、Domain、SameSite等),否则不会移除旧Cookie。FastEndpoints默认客户端的Cookie处理逻辑没有完整传递这些属性,导致删除指令不生效。

修复方案

1. 登出时指定正确的认证方案

确保登出用的认证方案和登录一致,避免默认方案不匹配:

if (User.Identity?.IsAuthenticated == true)
{
    var scheme = await HttpContext.GetCookieAuthenticationSchemeAsync();
    await HttpContext.SignOutAsync(scheme);
}

2. 完善Fixture的Cookie处理逻辑

修改UpdateCookies方法,使用请求的实际URI,并且手动解析Cookie属性确保完全匹配:

public void UpdateCookies(HttpResponseMessage response, Uri requestUri)
{
    if (!response.Headers.Contains("Set-Cookie")) return;

    foreach (var cookieHeader in response.Headers.GetValues("Set-Cookie"))
    {
        var cookieCollection = new CookieCollection();
        cookieCollection.SetCookies(requestUri, cookieHeader);
        
        foreach (Cookie cookie in cookieCollection)
        {
            if (cookie.Expires <= DateTime.Now)
            {
                // 发送明确的删除指令,匹配原始Cookie的Path属性
                CookieJar.SetCookies(requestUri, $"{cookie.Name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path={cookie.Path}");
            }
            else
            {
                CookieJar.Add(requestUri, cookie);
            }
        }
    }
}

3. 测试时传递正确的请求URI

调用UpdateCookies时,传入当前请求的完整URI,不要硬编码固定值:

// 登录并更新Cookie
var loginResponse = await Client.PostAsJsonAsync("/auth/login", loginRequest);
fixture.UpdateCookies(loginResponse, loginResponse.RequestMessage.RequestUri);

// 登出并更新Cookie
var logoutResponse = await Client.PostAsync("/auth/logout", null);
fixture.UpdateCookies(logoutResponse, logoutResponse.RequestMessage.RequestUri);

4. 验证Cookie状态(可选)

测试里可以手动检查CookieContainer,确认旧Cookie已被移除:

var cookies = fixture.CookieJar.GetCookies(new Uri("http://localhost"));
Assert.DoesNotContain(cookies, c => c.Name == ".AspNetCore.Identity.Application");

内容的提问来源于stack exchange,提问作者S. Schulz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:50:18