简体   繁体   English

OAuth 弹窗跨域安全 React.js

[英]OAuth popup cross-domain security React.js

I'm interested in how to implement OAuth in React using popup ( window.open ).我对如何使用弹出窗口( window.open )在 React 中实现 OAuth 很感兴趣。

For example I have:例如我有:

  1. mysite.com — this is where I open the popup. mysite.com — 这是我打开弹出窗口的地方。
  2. passport.mysite.com/oauth/authorize — popup. passport.mysite.com/oauth/authorize — 弹出窗口。

The main question is how to create connection between window.open (popup) and window.opener (as it's known the window.opener is null due to cross-domain security therefore we can't use it anymore). The main question is how to create connection between window.open (popup) and window.opener (as it's known the window.opener is null due to cross-domain security therefore we can't use it anymore).

window.opener is removed whenever you navigate to a different host (for security reasons), there is no way around it. window.opener每当您导航到不同的主机时都会被删除(出于安全原因),没有办法绕过它。 The only option should be doing the payment in a frame if it is possible.如果可能的话,唯一的选择应该是在一个框架内付款。 The top document needs to stay on the same host.顶部文档需要保留在同一主机上。

Scheme:方案:

在此处输入图像描述

Possible solutions:可能的解决方案:

  1. Check an opened window using setInterval described here .使用此处描述的setInterval检查打开的 window。
  2. Using cross-storage (not worth it imho ).使用跨存储(不值得恕我直言)。

So what's the best recommended approach in 2019?那么 2019 年最好的推荐方法是什么?

Wrapper for React - https://github.com/Ramshackle-Jamathon/react-oauth-popup React 的包装器 - https://github.com/Ramshackle-Jamathon/react-oauth-popup

Suggested by Khanh TO .Khanh TO建议。 OAuth popup with localStorage. OAuth 弹出本地存储。 Based on react-oauth-popup .基于react-oauth-popup

Scheme:方案:

在此处输入图像描述

Code:代码:

oauth-popup.tsx:

import React, {PureComponent, ReactChild} from 'react'

type Props = {
  width: number,
  height: number,
  url: string,
  title: string,
  onClose: () => any,
  onCode: (params: any) => any,
  children?: ReactChild,
}

export default class OauthPopup extends PureComponent<Props> {

  static defaultProps = {
    onClose: () => {},
    width: 500,
    height: 500,
    url: "",
    title: ""
  };

  externalWindow: any;
  codeCheck: any;

  componentWillUnmount() {
    if (this.externalWindow) {
      this.externalWindow.close();
    }
  }

  createPopup = () => {
    const {url, title, width, height, onCode} = this.props;
    const left = window.screenX + (window.outerWidth - width) / 2;
    const top = window.screenY + (window.outerHeight - height) / 2.5;

    const windowFeatures = `toolbar=0,scrollbars=1,status=1,resizable=0,location=1,menuBar=0,width=${width},height=${height},top=${top},left=${left}`;

    this.externalWindow = window.open(
        url,
        title,
        windowFeatures
    );

    const storageListener = () => {
      try {
        if (localStorage.getItem('code')) {
          onCode(localStorage.getItem('code'));
          this.externalWindow.close();
          window.removeEventListener('storage', storageListener);
        }
      } catch (e) {
        window.removeEventListener('storage', storageListener);
      }
    }

    window.addEventListener('storage', storageListener);

    this.externalWindow.addEventListener('beforeunload', () => {
      this.props.onClose()
    }, false);
  };

  render() {
    return (
      <div onClick={this.createPopup)}>
        {this.props.children}
      </div>
    );
  }
}

app.tsx

import React, {FC} from 'react'

const onCode = async (): Promise<undefined> => {
  try {
    const res = await <your_fetch>
  } catch (e) {
    console.error(e);
  } finally {
    window.localStorage.removeItem('code'); //remove code from localStorage
  }
}

const App: FC = () => (
  <OAuthPopup
    url={<your_url>}
    onCode={onCode}
    onClose={() => console.log('closed')}
    title="<your_title>">
    <button type="button">Enter</button>
  </OAuthPopup>
);

export default App;

I once encounter an issue on my oauth login flow with window.open/window.opener bug on ms-edge我曾经在我的 oauth 登录流程中遇到问题,在 ms-edge 上使用 window.open/window.opener 错误

My flow before this issue was在这个问题之前我的流程是

  • On login button click open a popup在登录按钮上单击打开一个弹出窗口
  • After successful login the oauth app redirect to my domain's page成功登录后 oauth 应用程序重定向到我的域页面
  • Then i call a function of the parent window from with in the popup (window.opener.fn) with data from oauth response and the parent window then close the child popup window Then i call a function of the parent window from with in the popup (window.opener.fn) with data from oauth response and the parent window then close the child popup window

My flow after this issue was这个问题之后我的流程是

  • On login button click open a popup在登录按钮上单击打开一个弹出窗口
  • Create a setinterval in case (window.opener is undefined)创建一个 setinterval 以防万一(window.opener 未定义)
  • After successful login the oauth app redirect to my domain's page成功登录后 oauth 应用程序重定向到我的域页面
  • Check if window.opener is available then do #3 from the above flow and clearInterval检查 window.opener 是否可用,然后从上述流程中执行 #3 并 clearInterval
  • If window.opener is not available then since i am on my domains page i try to set localstorage and try to read the localstorage from inside the setInterval function in parent window then clear the localstorage and setInterval and proceed.如果 window.opener 不可用,那么由于我在我的域页面上,我尝试设置 localstorage 并尝试从父 Z05B8C74CBD96FBF2DE4C1A352702 中的 setInterval function 内部读取 localstorage,然后清除 localstorage 并设置FBInterval4。
  • (for backward compatibility) If localstorage is also not available then set a client side cookie with the data with a short expiry (5-10 sec) time and try to read the cookie (document.cookie) inside the setInterval function in parent window and proceed. (为了向后兼容)如果 localstorage 也不可用,则设置一个客户端 cookie,其数据的有效期很短(5-10 秒),并尝试读取父 window 中的 setInterval function 内的 cookie(document.cookie)和继续。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM