使用ExpressJS框架实现登录后服务端向客户端写入Cookie时,搜狗或360等浏览器无法保存Cookie,主要原因是SetHeader时SameSite属性设置为None,Chrome内核低版本不支持None属性,解决方案是通过获取请求来源的user-agent,判断Chrome版本为80+SameSite值为None,低版本为Lax。(注意,如果SameSite为None 属性,那么该 Cookie 就必须同时加上 Secure 属性,表示只有在 HTTPS 协议下该 Cookie 才会被发送。)
Demo
var express = require('express');
var router = express.Router();
router.use((req, res, next) ={
......
// 判断Chrome Version80+支持SameSite=None
var deviceAgent = req.headers["user-agent"].toLowerCase();
// 获取浏览器信息
var broswer = getBroswer(deviceAgent)
var sameSite = 'Lax'
var isSupportNone = broswer.broswer === 'Chrome' && broswer.version.split('.')[0] >= 80
if (isSupportNone) { sameSite = 'None' }
res.setHeader('Set-Cookie', `token=${xxx};domain=${xxx};expires=${xxx};SameSite=${sameSite};Secure=${true};httpOnly=${true}`)
...
})
// 获取客户端浏览器信息
function getBroswer(ua) {
var Sys = {};
var s;
(s = ua.match(/edge\/([\d.]+)/)) ? Sys.edge = s[1] :
(s = ua.match(/rv:([\d.]+)\) like gecko/)) ? Sys.ie = s[1] :
(s = ua.match(/msie ([\d.]+)/)) ? Sys.ie = s[1] :
(s = ua.match(/firefox\/([\d.]+)/)) ? Sys.firefox = s[1] :
(s = ua.match(/chrome\/([\d.]+)/)) ? Sys.chrome = s[1] :
(s = ua.match(/opera.([\d.]+)/)) ? Sys.opera = s[1] :
(s = ua.match(/version\/([\d.]+).*safari/)) ? Sys.safari = s[1] : 0;
if (Sys.edge) return { broswer : "Edge", version : Sys.edge };
if (Sys.ie) return { broswer : "IE", version : Sys.ie };
if (Sys.firefox) return { broswer : "Firefox", version : Sys.firefox };
if (Sys.chrome) return { broswer : "Chrome", version : Sys.chrome };
if (Sys.opera) return { broswer : "Opera", version : Sys.opera };
if (Sys.safari) return { broswer : "Safari", version : Sys.safari };
return { broswer : "", version : "0" };
}
以下是解决过程中用到的资料汇总:
1、关于Cookie的SameSite详细介绍:
浏览器系列之 Cookie 和 SameSite 属性 github.com/mqyqingfeng…
2、判断浏览器的SameSite支持情况的测试工具:
3、官网关于SameSite详细的版本更新情况:
4、参考思路:
修复搜狗、360等浏览器不识别SameSite=None 引起的单点登录故障 www.cnblogs.com/JulianHuang…