Я хочу аутентифицировать пользователя с помощью механизма 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:
Проблема в том, что когда я нажимаю кнопку входа в Google, я получаю эту ошибку:
Я не знаю, почему 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
?