AJAX 请求不发送 cookie (NET 5)

Posted

技术标签:

【中文标题】AJAX 请求不发送 cookie (NET 5)【英文标题】:AJAX request not sending cookies (NET 5) 【发布时间】:2021-10-27 17:50:21 【问题描述】:

出于测试目的,设置了两个 Web 应用程序,一个“客户端”应用程序 (localhost) 和一个服务器应用程序(Azure Web 应用程序)。客户端向服务器发送 AJAX 请求并接收 cookie 作为响应。然后它再次对服务器进行 AJAX 调用,但请求中没有 cookie,它丢失了。

这是服务器配置(CORS 设置;https://localhost:44316 是我的“客户端”URL):

public class Startup

    public Startup(IConfiguration configuration)
    
        Configuration = configuration;
    

    public IConfiguration Configuration  get; 

    public void ConfigureServices(IServiceCollection services)
    
        services.AddCors(o => 
            o.AddPolicy("policy1", builder =>
                builder.WithOrigins("https://localhost:44316")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
        );

        services.AddControllers();
    

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseCors("policy1");

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        
            endpoints.MapControllers();
        );
    

这是第一个控制器,返回 cookie:

[Route("api/[controller]")]
[ApiController]
public class AController : ControllerBase

    [HttpPost]
    public IActionResult Post()
    
        var cookieOptions = new CookieOptions
        
            HttpOnly = true,
            Expires = DateTime.Now.AddMinutes(10),
            SameSite = SameSiteMode.None
        ;
        Response.Cookies.Append("mykey", "myvalue", cookieOptions);

        return Ok();
    

这是第二个控制器,它应该接收 cookie(但它没有):

[Route("api/[controller]")]
[ApiController]
public class BController : ControllerBase

    [HttpPost]
    public IActionResult Post()
    
        var x = Request.Cookies;

        return Ok(JsonConvert.SerializeObject(x));
    

这是来自“客户端”的调用脚本(分别是第一次和第二次调用):

function Go()

    $.ajax(
        url: 'https://somewebsite.azurewebsites.net/api/a',
        type: 'post',
        xhrFields: 
            withCredentials: true
        ,
        success: function (data, textStatus, jQxhr)
        
            console.log(data);
        ,
        error: function (jqXhr, textStatus, errorThrown)
        
            console.log(errorThrown);
        
    );


function Go2()

    $.ajax(
        url: 'https://somewebsite.azurewebsites.net/api/b',
        type: 'post',
        xhrFields: 
            withCredentials: true
        ,
        success: function (data, textStatus, jQxhr)
        
            console.log(data);
        ,
        error: function (jqXhr, textStatus, errorThrown)
        
            console.log(errorThrown);
        
    );

有人知道这可能是什么问题吗?

【问题讨论】:

您希望将 cookie 发送给第 3 方,或者您向同一个域/子域发出请求? "client" web 是一个站点,server web 是另一个站点,不涉及第 3 方。 如果我的回复有帮助,请采纳为答案(点击回复旁边的标记选项将其从灰色切换为填写。),请参阅meta.stackexchange.com/questions/5234/… 我的理解是,调用 Go 函数的响应标头应该包含 cookie,因此您不需要任何 MVC 结构来从运行在 Azure 上的应用程序接收它们? BController 在从 Go2 函数调用时必须接收这些 cookie,但情况并非总是如此(我正在使用最新的 Chrome、Firefox、Edge 和 Opera 进行测试)。我在这些浏览器中尝试了各种 cookie 设置,但没有帮助。无论如何,我正在努力理解和解决问题,而不是随便得到一些“似乎有效”的东西。 【参考方案1】:

正如this document 所说:

声明 SameSite=None 的 Cookie 也必须标记为安全

但你没有,所以改用这个:

var cookieOptions = new CookieOptions
            
                HttpOnly = true,
                Expires = DateTime.Now.AddMinutes(10),
                SameSite = SameSiteMode.None,
                Secure = true
            ;

这是我的测试结果:

【讨论】:

您的浏览器设置是什么?我的浏览器似乎接受或不接受 cookie,具体取决于第三部分 cookie 的设置? 边缘浏览器默认设置,我没有在浏览器上做任何设置。 那换个浏览器测试一下? 我测试了 4 种不同的浏览器,似乎问题在于浏览器(尽管它们之间存在一些细微差别)认为我的 cookie 是第 3 方,而第 3 方 cookie 的未来不会t 看起来很亮,即。已经是今天了,默认情况下它们在大多数浏览器中是不允许的。 @Marko 感谢您的回复,我从 Gary 那里看到了上面的答案,这也让我眼前一亮:)【参考方案2】:

我非常喜欢您在 SPA 从 API 获取 cookie 方面所做的工作。以下是根据处理这些问题的经验提出的一些建议。

问题

您正在从浏览器调用不同域中的 API,这意味着 cookie 是第三方的,现代浏览器会主动放弃它。

网站来源:localhost:44316 API 域:myazurewebapp.com

SameSite=None 是 standards docs 的理论解决方案,但这些通常不能解释当前浏览器的行为:

正如 Jason Pan 所说,您必须设置 Secure 属性 但它仍然无法在 Safari browser 和其他一些人中使用 预计在不久的将来会在 all browsers 中删除跨站点 cookie

解决方案

首选方案是设计托管域以便只使用first party cookie,许多软件公司都这样做了。可以通过在 Web 源的子域或同级域中运行 API 来完成:

网站来源:www.example.com API 域:api.example.com

在开发人员 PC 上,您只需更新主机文件即可完成此操作。另请注意,您可以在不同的端口上运行 Web 和 API 组件,它们将保持相同的站点:

127.0.0.1 localhost www.example.com api.example.com
:1        localhost

浏览器仍会发出 CORS 请求,但会认为 API 发出的 cookie 与 Web 源位于同一站点。然后,您还可以更改 cookie 设置以使用 SameSite=strict,以获得最佳安全性。

更多信息

在 Curity,我们最近发表了一些与您的问题密切相关的网络安全文章,因为 OpenID Connect 安全中使用的安全 cookie 也必须处理丢失的 cookie 问题:

Code Articles

【讨论】:

【参考方案3】:

您应该先了解AddTransientAddScoped 和AddSingleton。下面的帖子会对你有用。

AddTransient, AddScoped and AddSingleton Services Differences

而你需要使用AddSingleton,你会得到key的cookie值。

官方博客:How to work with cookies in ASP.NET Core

它对我有用,你可以在我提供的博客中找到示例代码。

我的测试

1.测试代码

2.在另一个控制器中测试结果。

【讨论】:

感谢您的帖子,但我不明白它的意义。您使用的命令与我用来设置和读取 cookie 的命令相同。您根本不使用 AJAX,这对于 POC 来说是必不可少的,因为它的行为与普通 MVC 不同(这就是我必须使用“withCredentials”代码的原因)。

以上是关于AJAX 请求不发送 cookie (NET 5)的主要内容,如果未能解决你的问题,请参考以下文章

为啥 jQuery 的 .ajax() 方法不发送我的会话 cookie?

Ajax 请求是不是保证发送 cookie?

CORS 请求 - 为啥不发送 cookie?

ASP.NET MVC - 在匿名 Ajax 请求上刷新 Auth Cookie

jQuery+ASP.NET MVC基于CORS实现带cookie的跨域ajax请求

使用 WIF 和 jquery ajax 请求时 ASP.NET MVC 3 中的会话 Cookie 过期处理