最近在使用IdentityServer的时候碰到谷歌浏览器无法登录的问题,查看网络发现如下错误提示:
The Set-Cookie was blocked because it had the “SameSite=None” attribute but did not have the secure attribute, which is required in order to use “SameSite=None”
原因是因为IdentityServer在写Cookie的时候使用的是SameSite=None属性,但是谷歌浏览器(大概是从版本80几开始)要求必须是HTTPS才能使用该属性,所以如果使用的是非HTTPS连接,那么就会碰到无法登录的问题。
当然最简单的解决办法就是使用HTTPS,毕竟IdentityServer是用来做认证的,理应使用更安全的HTTPS连接。
但是有些特殊情况,比如局域网内用IP地址访问的时候,应该怎么办呢?
其实我们可以通过修改Cookie的写入决策,在非HTTPS连接的时候移除SameSite属性即可。
修改Startup文件如下:
private const SameSiteMode Unspecified = (SameSiteMode)(-1);
public void ConfigureServices(IServiceCollection services)
{
//配置Cookie决策
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = Unspecified;
options.OnAppendCookie = cookieContext =>
SetSameSite(cookieContext.Context,cookieContext.CookieOptions);
options.OnDeleteCookie = cookieContext =>
SetSameSite(cookieContext.Context, cookieContext.CookieOptions);
});
//other service
}
public void SetSameSite(HttpContext httpContext, CookieOptions options)
{
if (options.SameSite == SameSiteMode.None)
{
//检测如果不是HTTPS,则移除SameSite属性
if (httpContext.Request.Scheme != "https")
{
//设置为Unspecified,则不会添加SameSite属性
options.SameSite = Unspecified;
}
}
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//使用Cookie决策
app.UseCookiePolicy();
//other middleware
}
关于SameSite,我们可以在Mozilla找到相关定义:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
这里也有篇很好的解释:
https://web.dev/samesite-cookies-explained/
简单点讲,她主要用来在请求URL的时候,控制浏览器是否接受和发送cookie, 有三个属性值:
- Strict: 最严格模式,只有请求的地址和浏览器的地址在同一个域名的时候,才会接受和发送Cookie。
- Lax:宽松模式,同一个域名会接受和发送,如果不在同一个域名,但是请求的地址为GET请求时,也会接受和发送Cookie,其他请求(POST,IFrame,Ajax,Image等)不会接受和发送cookie。
- None:始终接受和发送Cookie,但是对于谷歌浏览器来说,要求必须是HTTPS连接(估计以后其他浏览器也会跟进)。
IdentityServer为什么会使用None而不使用更为严格的Strict,Lax模式呢?
回顾前几篇关于Blazor与IdentityServer集成的例子
- Blazor与IdentityServer4的集成(一)
- Blazor与IdentityServer4的集成(二)
- Blazor与IdentityServer4的集成(三)
- Blazor与IdentityServer4的集成(四)
- Blazor与IdentityServer4的集成(五)
- Blazor与IdentityServer4的集成(六)
登录成功之后,我们查看Blazor页面的源代码,会看到如下iframe:
这是属于IdentityServer的地址,用来检查用户是否在线,显然她是需要发送Cookie的,所以只能使用SameSite=None。