AJAX 请求不发送 cookie (NET 5)
AJAX request not sending cookies (NET 5)
出于测试目的,设置了两个网络应用程序,一个“客户端”应用程序(本地主机)和一个服务器应用程序(Azure 网络应用程序)。客户端向服务器发送 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);
}
});
}
有谁知道这里的问题是什么?
你应该先知道AddTransient
、AddScoped
和AddSingleton。下面post对你有用。
并且你需要使用AddSingleton
,你将通过key获取cookie值。
官方博客:How to work with cookies in ASP.NET Core
它对我有用,你可以在我提供的博客中找到示例代码。
我的测试
1.测试码
2。在另一个控制器中测试结果。
正如this document所说:
Cookies that assert SameSite=None must also be marked as Secure
但你没有,所以用这个代替:
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Expires = DateTime.Now.AddMinutes(10),
SameSite = SameSiteMode.None,
Secure = true
};
这是我的测试结果:
就 SPA 从 API 获取 cookie 而言,我非常喜欢您在这里所做的事情的风格。以下是根据处理这些问题的经验提出的一些建议。
问题
您正在从浏览器调用另一个域中的 API,这意味着 cookie 是第三方的,现代浏览器会主动删除它。
- 网络来源:localhost:44316
- API 域:myazurewebapp.com
SameSite=None
是 standards docs 的理论解决方案,但这些通常不能解释当前的浏览器行为:
- 你必须设置
Secure
属性,正如 Jason Pan 所说
- 但它在 Safari browser 和其他一些
中仍然不起作用
- 预计在不久的将来 all browsers 会删除跨站点 cookie
解决方案
首选方案是设计托管域,以便只使用 first party
cookie,许多软件公司都这样做了。可以通过 运行 在网络来源的子域或兄弟域中 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 问题:
出于测试目的,设置了两个网络应用程序,一个“客户端”应用程序(本地主机)和一个服务器应用程序(Azure 网络应用程序)。客户端向服务器发送 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);
}
});
}
有谁知道这里的问题是什么?
你应该先知道AddTransient
、AddScoped
和AddSingleton。下面post对你有用。
并且你需要使用AddSingleton
,你将通过key获取cookie值。
官方博客:How to work with cookies in ASP.NET Core
它对我有用,你可以在我提供的博客中找到示例代码。
我的测试
1.测试码
2。在另一个控制器中测试结果。
正如this document所说:
Cookies that assert SameSite=None must also be marked as Secure
但你没有,所以用这个代替:
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Expires = DateTime.Now.AddMinutes(10),
SameSite = SameSiteMode.None,
Secure = true
};
这是我的测试结果:
就 SPA 从 API 获取 cookie 而言,我非常喜欢您在这里所做的事情的风格。以下是根据处理这些问题的经验提出的一些建议。
问题
您正在从浏览器调用另一个域中的 API,这意味着 cookie 是第三方的,现代浏览器会主动删除它。
- 网络来源:localhost:44316
- API 域:myazurewebapp.com
SameSite=None
是 standards docs 的理论解决方案,但这些通常不能解释当前的浏览器行为:
- 你必须设置
Secure
属性,正如 Jason Pan 所说 - 但它在 Safari browser 和其他一些 中仍然不起作用
- 预计在不久的将来 all browsers 会删除跨站点 cookie
解决方案
首选方案是设计托管域,以便只使用 first party
cookie,许多软件公司都这样做了。可以通过 运行 在网络来源的子域或兄弟域中 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 问题: