带有 React 和 Redux 的三足 OAuth

3 legged OAuth with React and Redux

在使用 Redux 的 React 中使用 OAuth2 进行身份验证的公认方法是什么?

我当前的设置涉及使用 Redux-Auth-Wrapper 包装 react-router 组件,如果用户未通过身份验证,则分派一个操作,向 OAuth 提供程序发出必要的外部 URL GET 请求(google 在这种情况下)。

OAuth2 需要在您的请求中发送一个回调 URL,所以我设置了一个反应路由器 url endpoint/component,当 onComponentDidMount 触发时,调度操作来解析返回来自 OAuth 提供程序的哈希,将该数据存储在 redux 存储中,并将用户重定向到他们最初请求的页面,该页面存储在 OAuth 请求的状态参数中。

这一切看起来都很老套。管理生产环境和开发环境之间的 OAuth2 回调 URL 也很困难。有人有流畅的 OAuth2 工作流程吗?

P.S。我需要将 Auth Token 获取到客户端,以便它可以用于发出客户端 API 使用该令牌检查用户是否有权访问这些资源的请求。

我想出了一个更好的解决方案,它涉及使用 OAuth 登录表单打开一个新的 window,然后由父级 window 轮询它是否已重定向到回调 URL。完成后,您可以使用包含父 window 中的 OAuth 令牌信息的散列捕获子 window url 并关闭子 window。然后您可以解析此哈希并将其添加到您的应用程序状态。

This tutorial 特别有帮助。

以下函数将从 google 获取令牌和过期数据并将其存储在本地存储中。它可以修改为简单地 return 该数据作为对象。

function oAuth2TokenGet() {
  // TODO: First try to get the token from sessionStorage here

  // Build the oauth request url
  const responseType = 'token';
  const clientId = 'YOUR-GOOGLE-CLIENT-ID';
  const redirectUri = 'YOUR-REDIRECT-URL';
  const scope = 'email profile';
  const prompt = 'select_account';
  const url = `https://accounts.google.com/o/oauth2/v2/auth?response_type=${responseType}&client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&prompt=${prompt}`;

  // Open a new window
  const win = window.open(url, 'name', 'height=600,width=450');
  if (win) win.focus();

  const pollTimer = window.setInterval(() => {
    try {
      if (!!win && win.location.href.indexOf(redirectUri) !== -1) {
        window.clearInterval(pollTimer);

        // Get the URL hash with your token in it
        const hash = win.location.hash;
        win.close();

        // Parse the string hash and convert to object of keys and values
        const result = hash.substring(1)
          .split('&')
          .map(i => i.split('='))
          .reduce((prev, curr) => ({
            ...prev,
            [curr[0]]: curr[1],
          }), {});

        // Calculate when the token expires and store in the result object
        result.expires_at = Date.now() + parseInt(hash.expires_in, 10);

        //  TODO: Persist result in sessionStorage here
      }
    } catch (err) {
      // do something or nothing if window still not redirected after login
    }
  }, 100);
}