使用 Iframe 跨域访问子页面无法获取 子页面的localstorage?

关于使用 Iframe 进行跨域访问 localstorage 的问题。
A 页面:http://127.0.0.1:5173/localstorage. 新窗口打开进行 localstorage.setItem("token", "test")
B页面:http://localhost:7456/localstorage.html 中想要访问 A 页面的 localstorage.

方法尝试使用 iframe和 postMessage进行传递。
在 B 页面使用 iframe 打开 A 页面,进行消息传递这些都没有问题。
关键问题:单独使用新窗口打开 A 页面localstorage.getItem("token")是有值的,但是使用 iframe 中打开 A 页面,就无法获取他的 localstorage。查看源是没有问题的啊
浏览器环境:Chrome,不是无痕模式。

希望有大佬帮忙解决一下这个问题。

如果把 A 页面的地址换成 http://localhost:5173/localstorage
或者把 B 页面的地址换成http://127.0.0.1:7456/localstorage.html
一切正常,但是这不就是同源了吗

添加截图和代码

这是单独窗口打开 A 页面,使用 127.0.0.1 打开。可以获取 localstorage

这是单独窗口打开 A 页面,使用 127.0.0.1 打开。可以获取 localstorage

这是 B 页面,使用 localhost:80802 打开。使用 iframe 打开 http://127.0.01:80801/a.html 却不能访问 A 的 localstorage
这是 B 页面,使用 localhost:80802 打开。使用 iframe 打开 http://127.0.01:80801/a.html 却不能访问 A 的 localstorage

如果将 B 使用 http://127.0.0.1:8082/b.html 打开,就可以获取的到

代码部分:
a.html

<html>
<header>
  A Page
</header>

<body>
  <script type="text/JavaScript">
    window.addEventListener('message', function (event) {
        if (event.origin === "http://127.0.0.1:8081")
            return;

        const localStorage = window.localStorage.getItem("test")
        console.log("localStorage data is: " + localStorage)

        // 监听父窗口发送过来的数据向服务器发送post请求
        const data = event.data
        console.log(event)
        const localData = window.localStorage.getItem('test')
        console.log(localData)
        window.parent.postMessage(localData, "*");
    }, false)
</script>
</body>

</html>

B.html

<html>
<header>
  B Page
</header>

<body>
<script type="text/JavaScript">
    const iframe = document.createElement('iframe')
    iframe.src = 'http://127.0.0.1:8081/a.html'
    document.body.appendChild(iframe)

    window.addEventListener("message", function (event) {
        if (event.origin !== "http://127.0.0.1:8081")
            return;

        const data = event.data;
        console.log(event);
    }, false);

    // window.onload = function () {
    //     window.frames[0].postMessage("hello", 'http://127.0.0.1:8081')
    // }
    setTimeout(() => {
        iframe.contentWindow.postMessage("hello", 'http://127.0.0.1:8081')
    }, 3000)
</script>
</body>

</html>
阅读 5k
avatarAI BotBETA

这个问题的关键在于浏览器的同源策略。同源策略是一种安全机制,它阻止了不同源的网页之间的某些类型的交互。当两个页面的协议、主机和端口都相同时,它们就被认为是同源的,可以自由地交互。

在你的例子中,A页面和B页面在不同的域上,因此它们被视为跨域。由于跨域限制,B页面无法访问A页面的localStorage。

但是,当你将A页面的地址改为http://localhost:5173/localstorage,或者将B页面的地址改为http://127.0.0.1:7456/localstorage.html时,它们都在相同的域上,因此不再被视为跨域,从而绕过了同源策略的限制。

为了解决这个问题,你可以尝试以下几种方法:

  1. 使用服务器代理:你可以设置一个服务器代理,将A页面和B页面都放在同一个域上,通过代理服务器进行通信。这样,B页面就可以访问A页面的localStorage了。
  2. 使用JSONP:JSONP是一种绕过同源策略的方法。你可以在A页面设置一个JSONP回调函数,并在B页面调用这个函数来获取数据。但是,请注意,JSONP只适用于GET请求,并且有一些安全风险。
  3. 使用CORS:CORS(跨来源资源共享)是一种更安全和更灵活的方法。你可以在服务器端设置适当的CORS头,允许B页面访问A页面的localStorage。但是,这需要服务器端的支持。

在你的情况下,使用服务器代理可能是最简单和最直接的方法。

2 个回答

可以获取到啊,看看你是不是有一些其他的业务代码影响到了?
还是说你的 Storage 里面本来就是空的,所以你获取不到?

图片.png


Edit 01/15/24

补充使用 localhost:8080 访问 127.0.0.1:8081 截图:
图片.png

Edit 01/16/24

所以OP其实想要做单点登录,那么简单的如果是同一个顶级域名下的不同的子域名。可以通过在设置 Cookie 时把 domain 设置为顶级域名。这样就会应用到顶级域名下的所有子域名。

如果不是同一个顶级域名下的,那么就是通过CAS的方式来实现单点登录,简易流程如下:

  1. 用户打开应用页面;
  2. 应用发现用户未登录;
  3. 跳转到 CAS server 登录页让用户登录;
  4. 登录成功,服务端生成 Service Ticket,并将 Ticket 作为参数携带跳转回应用;
  5. 应用获取 Ticket 参数并发送给后端验证;
  6. 后端验证 Ticket 是否有效,验证通过后完成登录操作。

单点登录(SSO)看这一篇就够了

推荐问题
logo
Microsoft
子站问答
访问
宣传栏