OAuth междоменная безопасность React.js - PullRequest
12 голосов
/ 06 ноября 2019

Меня интересует, как реализовать OAuth в React с помощью всплывающего окна (window.open).

Например, у меня есть:

  1. mysite.com - это где яоткройте всплывающее окно.
  2. passport.mysite.com/oauth/authorize - всплывающее окно.

Основной вопрос заключается в том, как создать соединение между window.open (всплывающее окно) и window.opener (как известно, window.opener имеет значение nullиз-за междоменной безопасности, поэтому мы больше не можем ее использовать).

window.opener удаляется всякий раз, когда вы переходите на другой хост (из соображений безопасности), нет никакого способа обойти это,Единственный вариант должен делать оплату в кадре, если это возможно. Верхний документ должен находиться на том же хосте.

Схема:

enter image description here

Возможные решения:

  1. Проверьте открытое окно, используя setInterval, описанное здесь .
  2. Используя кросс-хранилище (не стоит, imho).

Так какой же лучший рекомендуемый подход в 2019 году?

Оболочка для React - https://github.com/Ramshackle-Jamathon/react-oauth-popup

Ответы [ 2 ]

5 голосов
/ 09 ноября 2019

Предложено Khanh TO . OAuth всплывающее окно с localStorage. Основано на response-oauth-popup .

Схема:

enter image description here

Код:

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 App: FC = () => {

  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
    }
  }

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

export default App;
3 голосов
/ 14 ноября 2019

Однажды я столкнулся с проблемой в моем потоке входа в систему oauth с ошибкой window.open / window.opener на ms-edge

Мой поток до этой проблемы был

  • При входе в систему нажмите кнопку, чтобы открыть всплывающее окно
  • После успешного входа приложение oauth перенаправит на страницу моего домена
  • Затем я вызываю функцию родительского окна из с помощью всплывающего окна (окно. opener.fn) с данными из ответа oauth и родительским окном, затем закройте дочернее всплывающее окно

Мой поток после этой проблемы был

  • При нажатии кнопки входа откройте всплывающее окно
  • Создать setinterval в случае (window.opener не определен)
  • После успешного входа приложение oauth перенаправить на страницу моего домена
  • Проверить, доступен ли window.opener, затем сделать# 3 из вышеуказанного потока и clearInterval
  • Если window.opener недоступен, то, поскольку я нахожусь на своей странице доменов, я пытаюсь установить localstorage и пытаюсь прочитать localalstorage из функции setInterval в pзатем не открываете окно, затем очистите localstorage и setInterval и продолжите.
  • (для обратной совместимости) Если localstorage также не доступен, установите файл cookie на стороне клиента с данными с коротким сроком действия (5-10 секунд) и попробуйтечтобы прочитать cookie (document.cookie) внутри функции setInterval в родительском окне и продолжить.
...