如何配置 .net 核心以将身份验证 cookie 发送到不同的域

Posted

技术标签:

【中文标题】如何配置 .net 核心以将身份验证 cookie 发送到不同的域【英文标题】:How to configure .net core to send authentication cookies to different domain 【发布时间】:2018-08-19 12:10:04 【问题描述】:

我正在尝试将 cookie 用于前端的域与后端的域不同。后端是用 .net 核心实现的,前端是 Angular。 我研究过在进行 http 调用时需要设置 withCredentials: true 。但是当我将它设置为 true 时,我得到了这个错误:

对预检请求的响应未通过访问控制检查:当请求的凭据模式为“包含”时,响应中的“Access-Control-Allow-Origin”标头的值不得为通配符“*”。 我一直在尝试设置 CORS 和 Cookie 设置以应对这种情况。这是我来自 StartUp.cs 的相关代码。 Cors 设置:

services.AddCors(options =>
        
            options.AddPolicy("AllowDomainOrigin",
                builder =>
                
                    builder
                        .WithOrigins("http://some.domain.net")
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                );
            options.AddPolicy("AllowForLocalhost",
                builder =>
                
                    builder
                        .WithOrigins("http://localhost:4200")
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                );
        );
services.AddSession(options =>
        
            options.Cookie.SameSite = SameSiteMode.None;
        );
...
        app.UseCors("AllowDomainOrigin");
        app.UseCors("AllowForLocalhost");

Cookie 设置:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => 
            
                options.Cookie.Domain = "some.domain.net";
                options.Cookie.Name = "access_token";
                options.Cookie.SameSite = SameSiteMode.None;
                options.LoginPath = "/login";
                options.LogoutPath = "/login";
            )
            .AddCookie("localhost", options => 
            
                options.Cookie.Domain = "localhost";
                options.Cookie.Name = "localhost_access_token";
                options.Cookie.SameSite = SameSiteMode.None;
                options.LoginPath = "/login";
                options.LogoutPath = "/login";
            )
            .AddCookie("othercloud", options => 
            
                options.Cookie.Domain = "domain.com";
                options.Cookie.Name = "musiple_access_token";
                options.Cookie.SameSite = SameSiteMode.None;
                options.LoginPath = "/login";
                options.LogoutPath = "/login";
            )
            .AddJwtBearer(options => 
            
                options.TokenValidationParameters = tokenValidationParameters;
            );

这是我在登录控制器中登录 HttpContext 的方式:

await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync("localhost");
await HttpContext.SignOutAsync("othercloud");
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
            new ClaimsPrincipal(identity),
            authProperties);
await HttpContext.SignInAsync("localhost",
            new ClaimsPrincipal(identity),
            authProperties);
await HttpContext.SignInAsync("othercloud",
            new ClaimsPrincipal(identity),
            authProperties);

这是我的音频文件端点:

[HttpGet("id")]
[Authorize(AuthenticationSchemes= CookieAuthenticationDefaults.AuthenticationScheme +", localhost, othercloud")]
public async Task<FileStreamResult> Get(int id)

如您所见,我还将 JWT 令牌用于身份验证。我需要 cookie,因为我使用音频元素从我的 REST API 下载 mp3 文件,并且我将音频元素 src 直接设置为我的 REST API 地址。所以我不能在使用音频元素时将 JWT 设置为标题。当我的前端与后端位于同一域时,Cookies 在这种情况下运行良好,但现在我正尝试将前端移动到其他服务器和域。

我需要如何配置后端以获取来自不同域的 cookie?

我的后端在 Azure 上。还有一些 CORS 设置,我删除 * 并将其替换为特定地址。跟这个有关系吗?

编辑:

在我找到 Azure CORS 设置后,异常更改为:

对预检请求的响应未通过访问控制检查:响应中“Access-Control-Allow-Credentials”标头的值为“”,当请求的凭据模式为“包含”时,该值必须为“真”

编辑 2:

您需要从 Azure 中删除所有 CORS 设置以获取您的 .net 核心 cors 设置以获取 cors 控制权。仍然没有成功,但可能更接近解决方案。

【问题讨论】:

【参考方案1】:

我终于让它工作了。正如我在编辑评论中所说,主要原因是天蓝色 CORS 设置。删除它们后,我可以使用 .net 核心设置。这是我的最终解决方案: Cookie 设置:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => 
            
                options.Cookie.Name = "access_token";
                options.Cookie.SameSite = SameSiteMode.None;
            )
            .AddJwtBearer(options => 
            
                options.TokenValidationParameters = tokenValidationParameters;
            );

CORS 设置:

services.AddCors(options =>
        
            options.AddPolicy("AllowAllOrigins",
                builder =>
                
                    builder
                        .AllowAnyOrigin()
                        .AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowCredentials();
                );
        );
...

app.UseCors("AllowAllOrigins");

这是后台登录的相关代码:

await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
            new ClaimsPrincipal(identity),
            authProperties);

这在我的音频控制器端点就足够了

[HttpGet("id")]
[Authorize()]
public async Task<FileStreamResult> Get(int id)

在我进行登录调用时,我在前端设置了 withCredentials: true。

现在,当我使用 AllowAnyOrigin 而不是 WithOrigin 时,这是非常不安全的,但由于某种原因,我没有让它与 WithOrigin 一起使用。

对于正在阅读本文并在 azure 中使用 .net Core 并希望使用 CORS 的用户,请从 Azure 中删除您的 CORS 设置并在 .net core 中处理它们,因为在 .net core 中的配置比 azure 中的 CORS 多得多。以下是我从网上找到的一些资料:

https://feedback.azure.com/forums/169385-web-apps/suggestions/32371078-access-control-allow-credentials-not-set-in-creden https://github.com/Azure/azure-functions-host/issues/620 最后一个是有人使用 Azure 函数设置标头的链接,但是当我使用 .net 核心时,我发现这是完全错误的。

【讨论】:

以上是关于如何配置 .net 核心以将身份验证 cookie 发送到不同的域的主要内容,如果未能解决你的问题,请参考以下文章

如何同步表单身份验证 cookie 和 Asp.Net 会话的生命周期?

.Net SignalR 在还配置了 Cookie 身份验证时使用 JWT 承载身份验证

基于 Cookie 的身份验证

如何配置 ActiveMQ 以将“匿名”用户和角色分配给未经身份验证的用户

一段时间后,身份验证 cookie 在反应 SPA 中消失

如何使 ASP.NET Core 中的身份验证 cookie 无效?