问题
I want to authenticate a user using Google's Oauth2 mechanism. I have a React component with a button. The button's click handler makes an AJAX request to my server:
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);
In my server which is running at http://localhost:3000
and using Express.js I have middleware on all routes which handles 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();
};
This is the function which handles the route 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);
};
This is router which handles Google callback URL route:
router.get('http://localhost:3000/auth/google/callback',
passport.authenticate('google'), (req, res) => {
res.status(httpStatusCodes.OK).redirect('http://localhost:3005/home');
});
Also I made sure to enable the domains in Google dashboard:
The problem is when I click the Google sign in button I get this error:
I don't know what why CORS is a problem since I enabled domains from any origin in my server. From debug I see that the server route responsible for http://localhost:3000/auth/login
is called but Passport.js authenticate
method isn't called. In addition I know that my server authentication works if I enter http://localhost:3000/auth/login
in the browser address. But it doesn't work from my website. What could be my problem?
My browser is Chrome.
EDIT: I think I've found my problem: the function which handles the route http://localhost:3000/auth/login
has this code:
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);
};
Because my frontend runs at http://localhost:3005
and AJAX request from frontend is made to http://localhost:3000/auth/login
CORS is invoked. In the server when I get the request to the route http://localhost:3000/auth/login
I call passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next);
but I don't respond to the original request, therefore, CORS header is not set hence Chrome error. The problem is calling response.send()
after passport.authenticate
doesn't work. Also I don't see how I can respond to the request from inside passport.js. Is there a way to respond with response.send()
first and then call passport.authenticate
?
来源:https://stackoverflow.com/questions/55081056/why-fetching-a-server-api-which-triggers-oauth2-google-authentication-results-in