Почему загрузка серверного API, который запускает Oauth2-аутентификацию Google, приводит к ошибке `No 'Access-Control-Allow-Origin'`? - PullRequest
0 голосов
/ 09 марта 2019

Я хочу аутентифицировать пользователя с помощью механизма Google Oauth2. У меня есть компонент React с кнопкой. Обработчик нажатия кнопки отправляет AJAX-запрос на мой сервер:

import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/es/Button/Button';
import LinearProgress from '@material-ui/core/es/LinearProgress/LinearProgress';
import constants from '../../constants.js';
import { setGoogleAuthStatus, setLoggedInStatus } from '../../actions/appActions.js';

class Login extends React.Component {
  handleSignIn = () => {
    const { setLoggedInStatus } = this.props;

    fetch('http://localhost:3000/auth/login', {
      method: "GET"
    }).then(response => {
      console.log(`response=${response.text()}`);
      if (response.ok) {
        setLoggedInStatus(true);
      }
    }).catch(e => console.log(e));
  }

  render() {
    return (
      <div>
        <Button variant="contained" component="span"
        onClick={this.handleSignIn}>
          Sign in with Google
        </Button>
      </div>
    );
  }
}

Login.propTypes = {
  googleInit: PropTypes.bool.isRequired
};

const mapStateToProps = state => {
  return {
    googleInit: state.auth.googleInit
  };
};

const LoginConnected = connect(mapStateToProps,
  { setGoogleAuthStatus, setLoggedInStatus })(Login);
export default withRouter(LoginConnected);

На моем сервере, который работает на http://localhost:3000 и использует Express.js, у меня есть промежуточное ПО на всех маршрутах, которое обрабатывает CORS:

const allowCORS = (req, res, next) => {
  console.log('req.headers.origin = ' + req.headers.origin);
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');

  next();
};

Это функция, которая обрабатывает маршрут http://localhost:3000/auth/login:

const passportAuth = (req, res, next) => {
  console.log('from passportAuth');
  // Start OAuth 2 flow using Passport.js
  passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next);
};

Это маршрутизатор, который обрабатывает маршрут обратного вызова Google:

router.get('http://localhost:3000/auth/google/callback',
    passport.authenticate('google'), (req, res) => {
res.status(httpStatusCodes.OK).redirect('http://localhost:3005/home');
    });

Также я позаботился о том, чтобы включить домены в панели инструментов Google: enter image description here

Проблема в том, что когда я нажимаю кнопку входа в Google, я получаю эту ошибку:

enter image description here

Я не знаю, почему CORS является проблемой, поскольку я включил домены из любого источника на моем сервере. Из отладки я вижу, что серверный маршрут, отвечающий за http://localhost:3000/auth/login, вызывается, но метод Passport.js authenticate не вызывается. Кроме того, я знаю, что аутентификация моего сервера работает, если я ввожу http://localhost:3000/auth/login в адрес браузера. Но это не работает с моего сайта. В чем может быть моя проблема?

Мой браузер - Chrome.


РЕДАКТИРОВАТЬ: Я думаю, что я нашел свою проблему: функция, которая обрабатывает маршрут http://localhost:3000/auth/login имеет этот код:

const passportAuth = (req, res, next) => {
  console.log('from passportAuth');
  // Start OAuth 2 flow using Passport.js
  passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next);
};

Поскольку мой внешний интерфейс работает на http://localhost:3005, и AJAX-запрос от внешнего интерфейса выполняется на http://localhost:3000/auth/login Вызывается CORS. На сервере, когда я получаю запрос к маршруту http://localhost:3000/auth/login, я звоню passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next);, но я не отвечаю на исходный запрос, поэтому заголовок CORS не установлен, следовательно, ошибка Chrome. Проблема в вызове response.send(), после passport.authenticate не работает. Также я не вижу, как я могу ответить на запрос изнутри passport.js. Есть ли способ ответить сначала response.send(), а затем позвонить passport.authenticate?

...