You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SSO项目中iframe内Tomcat托管应用LocalStorage为空的排查与解决

跨域iframe中Tomcat托管应用LocalStorage为空的问题排查与解决

项目背景

我正在开发基于两个React应用的单点登录(SSO)项目:

  • 登录React应用:部署在Tomcat服务器,登录后将会话信息存入自身LocalStorage,并向父页面发送消息。
  • 本地React应用:本地开发环境运行在localhost:3000,通过iframe嵌入上述Tomcat托管的登录应用。

本地应用的iframe代码:

<iframe
  id="sso-iframe"
  src={`${process.env.REACT_APP_SSO_DOMAIN}/sso/#/sso`}
  style={{ height: 1000, width: 1000 }}
  title="SSO Sync"
></iframe>

已执行操作

  1. 单独登录Tomcat上的登录应用,确认其LocalStorage已正确存储会话和用户信息。
  2. 回到本地应用页面,查看浏览器开发者工具,能看到两个域名的LocalStorage条目,但Tomcat应用对应的LocalStorage为空。

已尝试的CORS配置

为Tomcat配置了CORS过滤器但未生效,配置内容如下:

<filter>
  <filter-name>CorsFilter</filter-name>
  <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
  <init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value>*</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.methods</param-name>
    <param-value>*</param-value>
  </init-param>
  <init-param>
    <param-name>cors.allowed.headers</param-name>
    <param-value>*</param-value>
  </init-param>
  <init-param>
    <param-name>cors.preflight.maxage</param-name>
    <param-value>3600</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>CorsFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

观察到的现象

  • 当两个应用分别运行在localhost:3000和localhost:3001时,iframe相关的LocalStorage能正常同步。
  • 只要能确保Tomcat应用的LocalStorage状态正确,后续SSO流程即可正常运行。

问题

Tomcat托管的登录应用在iframe中LocalStorage为空的原因是什么?该如何解决?


解决方案

1. 核心原因:浏览器同源策略限制

LocalStorage是同源绑定的,只有协议、域名、端口完全一致的页面才能共享或直接访问彼此的LocalStorage。当本地应用localhost:3000嵌入Tomcat部署的应用(假设域名是xxx.com:8080)时,两者属于不同源,父页面的开发者工具中看到Tomcat应用的LocalStorage为空,是浏览器的安全限制——它不允许跨源页面直接读取其他域的LocalStorage,而非iframe内部的LocalStorage真的为空。

你在localhost:3000和localhost:3001能正常工作,是因为测试时可能通过postMessage完成了数据同步,而非直接读取跨域LocalStorage;且浏览器会按域名+端口区分存储上下文,但跨域场景下的限制依然存在。

2. 正确的SSO数据同步方案

放弃直接读取跨域iframe的LocalStorage,改用postMessage跨域通信实现数据同步:

  • 登录应用在登录成功、写入LocalStorage后,主动向父页面发送会话信息:
    // 登录应用的登录成功回调逻辑
    const sessionData = localStorage.getItem('sessionInfo');
    // 指定父页面域名,避免恶意消息
    window.parent.postMessage(
      { type: 'SSO_LOGIN_SUCCESS', data: sessionData },
      process.env.REACT_APP_PARENT_DOMAIN
    );
    
  • 本地应用监听message事件,接收并存储会话信息:
    // 本地应用的组件挂载钩子中
    useEffect(() => {
      const handleSSOMessage = (event) => {
        // 验证发送方域名,防止非法请求
        if (event.origin !== process.env.REACT_APP_SSO_DOMAIN) return;
        if (event.data.type === 'SSO_LOGIN_SUCCESS') {
          localStorage.setItem('ssoSession', event.data.data);
          // 执行后续登录逻辑
        }
      };
      window.addEventListener('message', handleSSOMessage);
      return () => window.removeEventListener('message', handleSSOMessage);
    }, []);
    

3. Tomcat CORS配置的补充调整

如果登录应用的接口请求存在跨域问题,当前CORS配置需要补充允许携带凭证(SSO通常依赖Cookie或授权头):

<init-param>
  <param-name>cors.support.credentials</param-name>
  <param-value>true</param-value>
</init-param>

同时,将cors.allowed.origins从*改为具体的父页面域名(如http://localhost:3000)——当support.credentials设为true时,*是不被浏览器允许的。

4. 验证iframe内部的LocalStorage状态

要确认iframe中的登录应用是否真的写入了LocalStorage,不要通过父页面的开发者工具查看,而是直接在iframe上下文打开调试工具:右键点击iframe区域 → 选择“检查”,此时打开的工具属于iframe页面,可直接查看其LocalStorage的真实状态。


内容的提问来源于stack exchange,提问作者SoftwareNewbee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 18:53:20