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

如何通过GitHub OAuth授权React应用并实现授权后UI更新?

解决GitHub登录后React应用状态更新与用户信息展示问题

一、让主应用感知登录回调完成

因为登录流程用了弹窗,主窗口和弹窗同源,可通过两种方式让主应用感知登录成功:

方法1:使用postMessage跨窗口通信

  • 在回调页面(/login路由组件)中,拿到access_token和用户信息后,向主窗口发送消息并关闭弹窗:
    useEffect(() => {
      if (accessToken && userInfo) {
        // 向主窗口发送登录成功消息,限制同源避免风险
        window.opener.postMessage(
          {
            type: 'GITHUB_LOGIN_SUCCESS',
            accessToken,
            userInfo
          },
          window.location.origin
        );
        window.close();
      }
    }, [accessToken, userInfo]);
    
  • 在主应用根组件(如App.js)中监听消息,更新应用状态:
    useEffect(() => {
      const handleLoginSuccess = (event) => {
        if (event.origin !== window.location.origin) return;
        if (event.data.type === 'GITHUB_LOGIN_SUCCESS') {
          // 将用户信息存入组件状态或localStorage
          setUser(event.data.userInfo);
          localStorage.setItem('github_token', event.data.accessToken);
        }
      };
      window.addEventListener('message', handleLoginSuccess);
      // 组件卸载时清理监听
      return () => window.removeEventListener('message', handleLoginSuccess);
    }, []);
    

方法2:监听localStorage变化

  • 回调页面拿到数据后存入localStorage,再关闭弹窗:
    useEffect(() => {
      if (accessToken && userInfo) {
        localStorage.setItem('github_token', accessToken);
        localStorage.setItem('github_user', JSON.stringify(userInfo));
        window.close();
      }
    }, [accessToken, userInfo]);
    
  • 主应用监听storage事件(弹窗修改localStorage会触发主页面的该事件),同时页面加载时初始化状态:
    useEffect(() => {
      // 页面加载时检查本地存储
      const savedUser = localStorage.getItem('github_user');
      if (savedUser) setUser(JSON.parse(savedUser));
    
      // 监听存储变化
      const handleStorageChange = (event) => {
        if (event.key === 'github_user') {
          setUser(JSON.parse(event.newValue));
        }
      };
      window.addEventListener('storage', handleStorageChange);
      return () => window.removeEventListener('storage', handleStorageChange);
    }, []);
    

二、获取GitHub用户Profile数据

推荐通过后端代理请求GitHub API(避免前端暴露access_token),也可前端直接调用(不推荐):

后端代理方式(安全优先)

  • Node.js后端新增接口,用access_token请求GitHub用户接口:
    // Express示例
    app.get('/api/github/profile', async (req, res) => {
      const accessToken = req.headers.authorization?.split(' ')[1];
      if (!accessToken) return res.status(401).send('未授权');
    
      try {
        const githubRes = await fetch('https://api.github.com/user', {
          headers: { Authorization: `token ${accessToken}` }
        });
        const userData = await githubRes.json();
        res.json(userData);
      } catch (err) {
        res.status(500).send('获取用户信息失败');
      }
    });
    
  • React应用调用该接口获取完整用户数据:
    const fetchUserProfile = async (token) => {
      try {
        const res = await fetch('/api/github/profile', {
          headers: { Authorization: `Bearer ${token}` }
        });
        return await res.json();
      } catch (err) {
        console.error('获取用户信息失败:', err);
        return null;
      }
    };
    
    // 登录成功后调用
    if (accessToken) {
      const user = await fetchUserProfile(accessToken);
      setUser(user);
      localStorage.setItem('github_user', JSON.stringify(user));
    }
    

三、根据登录状态渲染UI

在组件中根据user状态切换显示登录按钮或用户头像:

function Header() {
  const [user, setUser] = useState(null);

  // 这里加入之前的状态初始化/监听逻辑

  return (
    <div className="header">
      {user ? (
        <div className="user-avatar">
          <img
            src={user.avatar_url}
            alt={`${user.login}的头像`}
            style={{ width: '40px', borderRadius: '50%' }}
          />
          <span>{user.login}</span>
        </div>
      ) : (
        <button
          onClick={() => window.open('/login', 'github-login', 'width=600,height=400')}
        >
          GitHub登录
        </button>
      )}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:55:15