首页 > 解决方案 > 当不在本地主机上时,在 OpenIdConnect 中间件 EventHandler 中添加的 Cookie 不会持续存在

问题描述

所以我使用 OpenId Connect 和AddOpenIdConnect配置方法来使用 Auth0 设置身份验证。我已经在本地使用它localhost作为我的 cookie 的域对其进行了全面测试,一切都很好!但是,一旦我将其发布到生产环境,cookie 似乎就不再存在了。疯狂的是我context.Response.Headers在方法之后直接记录了context.Response.Cookies.Append(...)它们,并且它们按预期在本地打印,但在生产中它们没有。

OnTokenValidated = (context) =>
{
    var accessToken = context.TokenEndpointResponse.AccessToken;

    var domain = HostingEnvironment.IsProduction() ? $"{cookieOptions.Domain}.{cookieOptions.Extension}" : "localhost";

    context.Response.Cookies.Append("access_token", accessToken, new CookieOptions
    {
        Domain = domain,
        SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax,
        Expires = DateTimeOffset.Now.AddHours(10),
        HttpOnly = true,
        Secure = HostingEnvironment.IsProduction(),
        Path = "/"
    });

    var idToken = context.TokenEndpointResponse.IdToken;

    context.Response.Cookies.Append("id_token", idToken, new CookieOptions
    {
        Domain = domain,
        SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax,
        Expires = DateTimeOffset.Now.AddHours(10),
        HttpOnly = false,
        Secure = HostingEnvironment.IsProduction(),
        Path = "/"
    });

    // Right here is where I can see the difference. Even though I am printing out the headers directly after appending them, they never are set in production.
    context.HttpContext.RequestServices.GetService<ILogger<Startup>>().LogWarning($"[HEADERS] {JsonConvert.SerializeObject(context.Response.Headers)}");

    return Task.CompletedTask;
},

我什至查看了 的实现,IResponseCookies.Append(...)看看会发生什么,但它非常简单,我看不出有任何方法可能无法将这些添加到标题中。

https://github.com/aspnet/HttpAbstractions/blob/bc7092a32b1943c7f17439e419d3f66cd94ce9bd/src/Microsoft.AspNetCore.Http/Internal/ResponseCookies.cs#L50

public void Append(string key, string value, CookieOptions options)
{
    if (options == null)
    {
        throw new ArgumentNullException(nameof(options));
    }

    var setCookieHeaderValue = new SetCookieHeaderValue(
        Uri.EscapeDataString(key),
        Uri.EscapeDataString(value))
    {
        Domain = options.Domain,
        Path = options.Path,
        Expires = options.Expires,
        MaxAge = options.MaxAge,
        Secure = options.Secure,
        SameSite = (Net.Http.Headers.SameSiteMode)options.SameSite,
        HttpOnly = options.HttpOnly
    };

    var cookieValue = setCookieHeaderValue.ToString();

    Headers[HeaderNames.SetCookie] = StringValues.Concat(Headers[HeaderNames.SetCookie], cookieValue);
}
        

标签: cookies.net-core

解决方案


好的,所以我终于想通了。ASP .NET Core 3.x的Auth0 快速入门包含以下代码行:

services.Configure<CookiePolicyOptions>(options =>
{
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
});

这强制要求所有 Cookie 都需要“同意”。我还没有弄清楚这意味着什么,因为 MS 文档似乎非常有限。将其更改为之后false,一切都重新开始工作。false是默认设置,只是 Auth0 快速入门出于某种原因添加了它。

进一步导致我困惑的是,我试图查看 ResponseCookies 的实现,Cookies.Append(...)然后我找到了实现的ResponseCookies类,IResponseCookies并最终将该实现复制/粘贴到我的代码中以使其正常工作。挖掘之后,我意识到它不是这个实现,而是这个ResponseCookiesWrapper实际上正在使用。正如你所看到的,这个实现使用了所有额外的“同意”逻辑来确保你被允许添加一个显然我没有添加的 cookie。

更新:对不起,我提到的是我只在 localhost 上工作,但你可能会问为什么它在 localhost 和 PROD 上没有失败。这是因为即使快速入门显示它硬编码为, GitHub 上true的实际示例代码也使用了我所拥有的。HostingEnvironment.IsProduction()


推荐阅读