MERN OAuth实施不重定向到Google登录页面

时间:2020-06-02 16:22:24

标签: node.js reactjs express passport.js passport-google-oauth

我当前正在使用MERN堆栈运行网络服务器,并且正在尝试使OAuth登录正常运行。但是,当我单击“使用google登录”按钮时,react会加载主页(但URL会更改)。直接获取URL会从服务器获得302响应,但是前端没有变化。

Server.js

const express = require('express');
const path = require('path');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const logger = require('morgan');
const cors = require('cors');
const secure = require('express-force-https');
const passport = require('passport');
const cookieSession = require('cookie-session');

require('dotenv').config();

const app = express();
const port = process.env.PORT || 5000;
const dbRoute = process.env.MONGODB_URI || 'NO DB ROUTE PROVIDED';

// db setup
mongoose.connect(
  dbRoute,
  {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    dbName: process.env.DATABASE_NAME,
  }
);

let db = mongoose.connection;
db.once('open', () => console.log("Connected to the database"));
db.on('error', console.error.bind(console, "MongoDB connection error: "));

// middleware
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false })); // body parsing
app.use(bodyParser.json());
app.use(logger("dev"));
app.use(express.static(path.join(__dirname, "client", "build"))); // for serving up the clientside code
app.use(secure); // ensure that the connection is using https
app.use(cookieSession({ // cookies!
  maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
  keys:['vcxzkjvasddkvaosd'] // yeah i'm sure that's secure enough
}));

// models
require('./models/rule');
require('./models/affix');
require('./models/user');

// passport security
require('./config/passport');
app.use(passport.initialize());
app.use(passport.session());

// routes
app.use(require('./routes'));

// The "catchall" handler: for any request that doesn't
// match one above, send back React's index.html file.
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname+'/client/build/index.html'));
});

app.listen(port);

console.log(`Server listening on ${port}`);

路由(不同文件夹中有一些索引文件,因此该路由的完整路径为/api/user/google

const mongoose = require('mongoose');
const passport = require('passport');
const router = require('express').Router();
const auth = require('../auth');
const User = mongoose.model('User');

router.get('/google', 
  passport.authenticate('google', {
    scope: ['profile', 'email']
  })
);

router.get('/google/callback', 
  passport.authenticate('google', { failureRedirect: '/affixes'}),
  (req, res) => {
    res.redirect('/?token=' + req.user.token);
  }
);

Passport.js

const mongoose = require('mongoose');
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
require('dotenv').config();

const User = mongoose.model('User');

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id).then((user) => {
    done(null, user);
  })
});

passport.use(new GoogleStrategy({
    clientID: process.env.OAUTH_CLIENT_ID,
    clientSecret: process.env.OAUTH_CLIENT_SECRET,
    callbackURL: '/api/user/google/callback',
    proxy: true
  },

  (accessToken, refreshToken, profile, done) => {
    User.findOne({ googleId: profile.id })
      .then((existingUser) => {
        if (existingUser) {
          done(null, existingUser);
        } else {
          new User({ googleId: profile.id }).save()
            .then((user) => done(null, user));
        }
      });
  }
));

前端登录页面(具有获取按钮和链接按钮。如上所述,行为不同)

import React from 'react';
import {
  ComingSoon
} from '../Common';
import {
  Button
} from '@material-ui/core';

const handleClick = () => {
  fetch('/api/user/google')
}

export default function Login() {
  return (
    <>
      <Button onClick={handleClick}>
        Login with Google
      </Button>

      <a href="/api/user/google"><button>Log in with Google</button></a>
    </>
  );
}

更新:看起来有点像CORS问题,尽管我仍然不知道如何解决它。浏览器吐出

Access to fetch at '...' (redirected from 'http://localhost:3000/api/user/google') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

添加请求的标头会给我

Access to fetch at '...' (redirected from 'http://localhost:3000/api/user/google') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

1 个答案:

答案 0 :(得分:0)

事实证明,我对这个问题的本质是完全错误的!问题是我对OAuth端点的提取请求正在调用我的前端,而不是后端,因为该请求的text/html标头中包含Accept。使用react高级代理设置来路由到正确的URI解决了该问题。

请参阅:https://github.com/facebook/create-react-app/issues/5103https://github.com/facebook/create-react-app/issues/8550