本地联调单点登录,iframe跨域cookie丢失

慢条斯理的小可

背景

需求:A站点内用iframe嵌入B站点,需实现单点登录。

问题:我在本地调试时,由于本地开发环境A、B不同域,便手动给本地(嵌入的B站点)添加cookie,A站点内的B站点能正常自动带上cookie请求后台接口。
但是,同样代码,在小伙伴那遇到问题,发现iframe嵌入的B站点请求接口时未带上cookie

分析

因为我chrome版本比较低,总会遇到一些兼容问题,大概率是浏览器版本的区别(类似这种跨域遇到的问题,一般是由于浏览器的安全策略)。
iframe cookie(丢失)就出来很多相关解释。

原因

浏览器的Cookie新增了SameSite属性(用来防止CSRF攻击用户追踪 - 推荐阅读【2】有相关介绍)。
chrome 80+将未声明SameSite值的Cookie默认设置为SameSite=Lax Cookie(大多数情况不发送第三方Cookie)。

解决方案

参考下面推荐阅读文章,简单列一下几种解决方案:

1、客户端解决方案

通过设置chrome浏览器相关策略开关,如

  • 低于91版本的chrome,disabled这2个flag:

    • same-site-by-default-cookies
    • cookies-without-same-site-must-be-secure
  • 91及以上,且94以下版本,设置浏览器features(可参考推荐阅读【3】)

    • --disable-features=SameSiteByDefaultCookies
  • 94及以上版本,上述设置都不支持了,即浏览器全面禁止三方cookie

    PS:客户端解决方案只适用于本地联调,只作用于本地浏览器;而且高版本浏览器现在都不支持了。

因此,针对开头提到的场景,后面B站点可能要采取localStorage共享cookie数据,然后在请求头加_cookie参数请求B站点服务器接口,有服务器再作一层校验。

2、服务器解决方案

https协议 + SameSite=None
PS:后面有亲测例子

推荐阅读【1】也提到浏览器将全面禁止第三方cookie,因此,前端跨域cookie的问题,得换个角度去解决,比如在客户端跨域请求变成非跨域,想办法获取cookie后存起来用其他方式传输(如【1】的第四个“代理服务”方案)

3、代理服务

思路:先解决跨域,再解决cookie传输问题。

PS:每个应用场景不同,这里只是个人尝试解读【1】第4个代理服务方案的场景

场景:C网站(假设域名C.com) 请求 D后台服务的登陆校验接口(假设域名D.com),登陆后需记录其登陆信息cookie,然后获取用户信息。
流程设计:

  1. 添加一层C'站点(与C同域),作为代理服务器,把登陆请求先发给C'(基于iframe+postMessage跨域);
  2. 中间代理服务器C',再向目标服务器D发起真正的后台请求进行登陆校验,把response返回的cookie同步返回给C'网站;
  3. 需要获取当前登陆的用户信息时,把cookie放在请求头的_cookie参数里请求C'的fetchUser接口,C'服务器把_cookie再塞进headercookie里请求D真实的fetchUser接口;

在这,我有以下疑惑🤔:

  • 第1步,为什么用iframe的方式去跨域请求C'的接口,为什么不直接C跨域请求C'代理服务的接口(即网站项目http://127.0.0.1:8000像第3步-查询数据一样,直接请求8001/login是不是也行)?
  • 如果C站点本身有自己的后台服务,直接作为代理服务器,就不用再考虑C网站跨域请求的cookie问题了?如果C站点可控的话,这种方式更方便?

    欢迎大家戳戳留下脚印,欢迎留言交流哦~

其他相关

亲测服务器解决方案(跨域Set-Cookie

浏览器:Chrome版本 102.0.5005.61

A)网站web parent

http://127.0.0.1:5501/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>web parent</title>
</head>
<body>
    web parent
    <iframe src="http://localhost:5502/index.html"></iframe>
</body>
</html>
B)网站web sub

(http://localhost:5502/index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>web sub</title>
    <script src="https://cdnjs.gtimg.com/cdnjs/libs/zepto/1.1.4/zepto.js"></script>
</head>
<body>
    web sub
    <script type="text/javascript">
        console.log('web sub', '1 document.cookie', document.cookie);
        var addCookie = function (name, value, time) {
            var strSec = time;
            var exp = new Date();
            exp.setTime(exp.getTime() + strSec * 1);
            document.cookie = name + "=" + value + ";expires=" + exp.toGMTString() ;// + ";SameSite=None;Secure";
        }
        console.log('set cookie', 'web_sub_cookie', 'I_AM_SUB_COOKIE');
        addCookie('web_sub_cookie', 'I_AM_SUB_COOKIE',600000);
        console.log('web sub', '2 document.cookie', document.cookie);
    </script>
</body>
</html>
  • 单独访问网站web sub时,可看到cookie设置成功
    image.png
  • 但新标签页打开网站web parent时,却访问不到该cookie,也设置不了cookie
    image.png
  • 设置cookie时加上'SameSite=None;Secure'会设置不成功
C)添加网站web sub的服务器接口

(http://localhost:5503/setCookie)

// 1、加载模块
const http = require('http');
// 2、创建http
var server = http.createServer(); // 创建一个web容器 静态服务器
// 3、监听请求事件
server.on('request', function (request, response) {
    // 监听到请求之后所做的操作
    var url = request.url;
    if (url === '/setCookie') {
        response.writeHead(200, {
            'Content-Type': 'application/json',
            'Set-Cookie': ['web_sub_service_cookie=I_AM_WEB_SUB_SERVICE_COOKIE;']
        });
        response.end(JSON.stringify({}));
    }
})
// 4、监听端口,开启服务
server.listen(5503, function () {
    console.log("服务器已经启动,可访问以下地址:");
    console.log('http://localhost:5503');
})

启动上述node服务,在web parent站点用iframe引用web sub站点服务器接口

<iframe src="http://localhost:5503/setCookie"></iframe>

web sub站点服务器responseset-cookie是默认被禁用的
image.png
加上SameSiteSecure就可以

'Set-Cookie': ['web_sub_service_cookie=I_AM_WEB_SUB_SERVICE_COOKIE;SameSite=None;Secure'],

image.png
这个cookie如上设置属性之后,跨域下可设置、读取。(在chrome 102版本上测试ok)

在文章【4】里提到:

Chrome 也宣布,将在下个版本也就是 Chrome 83 版本,在访客模式下禁用三方 Cookie,在 2022年全面禁用三方 Cookie,到时候,即使你能指定 SameSiteNone也没有意义,因为你已经无法写入第三方Cookie了。

目前亲测还能用,应该在不久后就会全面禁用的。

推荐阅读

阅读 982
2 声望
1 粉丝
0 条评论
2 声望
1 粉丝
文章目录
宣传栏