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

如何在父窗口访问子窗口信息?React子窗口OAuth认证后回写父页

在React中实现父窗口获取子窗口认证状态的方案

我来帮你梳理下实现这个需求的具体步骤,核心是利用浏览器的window.open保存子窗口引用,再通过postMessage做跨窗口安全通信,完美适配你描述的OAuth认证流程:

1. 父组件中保存子窗口引用并监听消息

首先在父组件里,我们需要管理弹窗的显示状态、认证状态,还要保存打开的认证子窗口引用,同时监听子窗口发过来的消息:

import { useState, useRef, useEffect } from 'react';
import AuthModal from './AuthModal';

function ParentComponent() {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [authStatus, setAuthStatus] = useState(null); // 可选值:null/success/failed/cancelled
  const authWindowRef = useRef(null); // 保存子窗口引用

  // 处理子窗口发来的消息
  const handleMessage = (event) => {
    // 🔒 一定要验证消息来源,替换成你的回调页面域名,防止恶意消息
    if (event.origin !== 'https://your-callback-domain.com') return;

    if (event.data.type === 'AUTH_SUCCESS') {
      setAuthStatus('success');
      authWindowRef.current?.close(); // 认证成功后关闭子窗口
      setIsModalOpen(false);
    } else if (event.data.type === 'AUTH_FAILED') {
      setAuthStatus('failed');
    }
  };

  // 打开OAuth认证窗口
  const openAuthWindow = () => {
    // 配置窗口大小和位置,按需调整
    const windowConfig = 'width=600,height=700,top=150,left=200';
    authWindowRef.current = window.open(
      'https://your-oauth-provider-auth-url.com', // 替换成OAuth服务商的授权地址
      'OAuthAuthWindow',
      windowConfig
    );

    // 兜底监听:如果用户中途关闭子窗口,标记为取消
    const checkWindowClosed = setInterval(() => {
      if (authWindowRef.current?.closed) {
        clearInterval(checkWindowClosed);
        if (authStatus !== 'success') {
          setAuthStatus('cancelled');
        }
      }
    }, 500);
  };

  // 组件挂载时添加消息监听,卸载时清理
  useEffect(() => {
    window.addEventListener('message', handleMessage);
    return () => {
      window.removeEventListener('message', handleMessage);
      authWindowRef.current?.close(); // 组件卸载时关闭子窗口
    };
  }, []);

  return (
    <div className="parent-container">
      <button onClick={() => setIsModalOpen(true)} className="add-new-btn">Add New</button>

      {isModalOpen && (
        <AuthModal
          onClose={() => setIsModalOpen(false)}
          onStartAuth={openAuthWindow}
          authStatus={authStatus}
        />
      )}
    </div>
  );
}

export default ParentComponent;

2. 弹窗组件(AuthModal)

弹窗里主要负责显示操作按钮和认证状态提示:

import React from 'react';

function AuthModal({ onClose, onStartAuth, authStatus }) {
  return (
    <div className="modal-overlay">
      <div className="modal-card">
        <h3>Link Your Account</h3>
        {authStatus === null && (
          <button onClick={onStartAuth} className="auth-btn">Start Authorization</button>
        )}
        {authStatus === 'success' && <p className="success-msg">✅ Authorization successful!</p>}
        {authStatus === 'failed' && <p className="error-msg">❌ Authorization failed, please try again.</p>}
        {authStatus === 'cancelled' && <p className="info-msg">ℹ️ Authorization cancelled.</p>}
        <button onClick={onClose} className="close-btn">Close</button>
      </div>
    </div>
  );
}

export default AuthModal;

3. 回调页面发送认证状态给父窗口

当OAuth认证完成后,会跳转到你的回调页面,这里需要向父窗口发送认证结果:

如果你的回调页面是静态HTML:

<!DOCTYPE html>
<html>
<body>
  <script>
    // 从URL参数中获取OAuth返回的结果(比如code或error)
    const params = new URLSearchParams(window.location.search);
    const hasError = params.has('error');

    // 向父窗口发送消息,🔒 最好指定父窗口域名,不要用*
    if (window.opener) {
      window.opener.postMessage(
        { type: hasError ? 'AUTH_FAILED' : 'AUTH_SUCCESS' },
        'https://your-parent-app-domain.com'
      );
    }

    // 延迟1秒后关闭窗口,让用户看到提示
    setTimeout(() => window.close(), 1000);
  </script>
  <p>Processing authorization... This window will close shortly.</p>
</body>
</html>

如果回调页面是React组件:

import { useEffect } from 'react';

function AuthCallback() {
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const error = params.get('error');
    const code = params.get('code');

    // 构造消息
    const message = error 
      ? { type: 'AUTH_FAILED', error: error }
      : { type: 'AUTH_SUCCESS', code: code };

    // 发送给父窗口
    if (window.opener) {
      window.opener.postMessage(message, 'https://your-parent-app-domain.com');
    }

    // 关闭窗口
    setTimeout(() => window.close(), 1000);
  }, []);

  return (
    <div className="callback-container">
      <p>Processing your authorization...</p>
    </div>
  );
}

export default AuthCallback;

关键注意事项

  • 安全第一:postMessage一定要验证event.origin,发送消息时指定明确的目标域名,避免跨站攻击。
  • 内存泄漏防范:组件卸载时要移除消息监听、关闭子窗口,清理引用。
  • OAuth配置:确保你的回调URL已经在OAuth服务商的后台配置好,否则会出现跳转失败的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:02:39