Bảo mật đa miền bật lên OAuth React.js


12

Tôi quan tâm đến cách triển khai OAuth trong React bằng popup ( window.open).

Ví dụ tôi có:

  1. mysite.com - đây là nơi tôi mở cửa sổ bật lên.
  2. passport.mysite.com/oauth/authorize - cửa sổ bật lên.

Câu hỏi chính là làm thế nào để tạo kết nối giữa window.open(cửa sổ bật lên) và window.opener(như được biết window.opener là null do bảo mật tên miền chéo do đó chúng tôi không thể sử dụng nó nữa).

Bị window.openerxóa bất cứ khi nào bạn điều hướng đến một máy chủ khác (vì lý do bảo mật), không có cách nào xung quanh nó. Tùy chọn duy nhất nên thực hiện thanh toán trong một khung nếu có thể. Các tài liệu hàng đầu cần phải ở trên cùng một máy chủ.

Kế hoạch:

nhập mô tả hình ảnh ở đây

Phương pháp khả thi:

  1. Kiểm tra một cửa sổ mở bằng cách sử dụng setIntervalmô tả ở đây .
  2. Sử dụng lưu trữ chéo (không đáng imho).

Vì vậy, cách tiếp cận được đề xuất tốt nhất trong năm 2019 là gì?

Trình bao bọc cho phản ứng - https://github.com/Ramshackle-Jamathon/react-oauth-popup


2
Năm 2019, hỗ trợ localStorage tốt hơn nhiều. Tôi sẽ sử dụng phương pháp localStorage (được mô tả trong stackoverflow.com/questions/18625733/ mẹo ) vì nó có vẻ không giống như một cách giải quyết. Cửa sổ cha không cần kiểm tra định kỳ trạng thái cửa sổ con. setIntervalcó thể được sử dụng làm dự phòng cho localStorage
Khánh đến

@KhanhTO, vâng, tôi hoàn toàn đồng ý với bạn localStorage, nhưng nó chỉ hoạt động cho cùng một tên miền nên nó không hoạt động trong điều kiện của tôi
Arthur

2
Sau khi bạn kết thúc với OAuth, cửa sổ con được chuyển hướng trở lại tên miền của bạn, bây giờ bạn đang ở trong cùng một miền với cha mẹ
Khánh đến

@KhanhTO, hm, đây là ý tưởng tuyệt vời! Tôi nên biết ..
Arthur

1
Sẽ tốt hơn nữa nếu trình duyệt khôi phục window.openersau khi chuyển hướng trở lại miền của chúng tôi, nhưng đây không phải là trường hợp
Khánh đến

Câu trả lời:


6

Đề nghị của Khánh ĐẾN . Cửa sổ bật lên OAuth với localStorage. Dựa trên phản ứng-oauth-popup .

Kế hoạch:

nhập mô tả hình ảnh ở đây

Mã số:

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;

3

Tôi đã một lần gặp sự cố về luồng đăng nhập oauth của mình với lỗi window.open/window.opener trên ms-edge

Dòng chảy của tôi trước vấn đề này là

  • Trên nút đăng nhập, nhấp vào mở một cửa sổ bật lên
  • Sau khi đăng nhập thành công, ứng dụng oauth chuyển hướng đến trang của tên miền của tôi
  • Sau đó, tôi gọi một chức năng của cửa sổ cha mẹ từ trong cửa sổ bật lên (window.opener.fn) với dữ liệu từ phản hồi oauth và cửa sổ cha mẹ sau đó đóng cửa sổ bật lên con

Dòng chảy của tôi sau vấn đề này là

  • Trên nút đăng nhập, nhấp vào mở một cửa sổ bật lên
  • Tạo một setinterval trong trường hợp (window.opener không xác định)
  • Sau khi đăng nhập thành công, ứng dụng oauth chuyển hướng đến trang của tên miền của tôi
  • Kiểm tra xem window.opener có khả dụng không, sau đó thực hiện # 3 từ luồng trên và ClearInterval
  • Nếu window.opener không khả dụng thì vì tôi đang ở trang tên miền của mình, tôi cố gắng đặt localst Storage và cố gắng đọc localst Storage từ bên trong hàm setInterval trong cửa sổ cha mẹ, sau đó xóa localst Storage và setInterval và tiến hành.
  • (để tương thích ngược) Nếu lưu trữ cục bộ cũng không khả dụng thì hãy đặt cookie phía máy khách với dữ liệu có thời gian hết hạn ngắn (5-10 giây) và cố gắng đọc cookie (document.cookie) bên trong hàm setInterval trong cửa sổ cha mẹ và tiến hành
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.