Получение ошибки CORS при использовании PassportJS для Google OAuth в React/Express

#javascript #reactjs #express #google-oauth #passport.js

Вопрос:

Несмотря на многочасовые поиски, я не могу найти решение своей простой ошибки cors. Я получаю следующее в браузере:

Доступ к XMLHttpRequest по адресу ‘https://accounts.google.com/o/oauth2/v2/auth?response_type=codeamp;redirect_uri=http://localhost:3001/api/auth/auth/google/callbackamp;scope=profile emailamp;client_id=******.apps.googleusercontent.com’ (перенаправлено с ‘http://localhost:3000/api/auth/auth/google’) от источника ‘http://localhost:3000″ заблокирован политикой CORS: на запрошенном ресурсе отсутствует заголовок «Управление доступом-Разрешить-Происхождение».

Я только что заменил идентификатор клиента по соображениям безопасности для этого поста. Когда я делаю этот звонок в клиенте Postman/Thunder, он возвращает 200 ответов и, кажется, работает нормально

Поэтому я попытался использовать пакет cors NPM в express app.use(cors()); , а также попытался использовать эту функцию в server.js app.all("/*", function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); next(); }); Я также пробовал использовать `

 const proxy = require('http-proxy-middleware');

module.exports = function(app) {
    app.use(proxy("/api/auth/auth/google", {
          target: "https://localhost:3000/",
          changeOrigin: true
    }));
}
 

Я почти выполнил все решения в книге, которые нашел в SO, и до сих пор ни одно из них, похоже, не работало. Любая помощь была бы так признательна, вот мой код:

Package.json в клиенте

 {
  "name": "tasktracker",
  "proxy": "http://localhost:3001/",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.13.0",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "axios": "^0.21.1",
    "http-proxy-middleware": "^2.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
 

Homepage.js

 import React from "react";
import API from "../components/utils/API";

export default function HomePage() {
  const handleLogin = () => {
    API.login();
  };
  const testing = () => {
    console.log("Hello world!");
    API.testing();
  };

  return (
    <div>
      <h1>Let's login with Google</h1>
      <button onClick={handleLogin}>Login</button>
      <button onClick={testing}>Testing</button>
    </div>
  );
}
 

API.js

 import axios from "axios";
export default {
  login: function () {
    return axios.get("/api/auth/auth/google");
  },
  testing: function () {
    return axios.get("/api/auth/test");
  },
};
 

Server.js

 const express = require("express");
const passport = require("passport");
const routes = require("./routes");
const app = express();
const PORT = process.env.PORT || 3001;
const cors = require("cors");

app.use(cors());

// Define middleware here
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
require("./config/passport");
app.use(passport.initialize());

// Add routes, both API and view
app.use(routes);


// Start the API server
app.listen(PORT, function () {
  console.log(`🌎  ==> API Server now listening on PORT ${PORT}!`);
});
 

auth.js (auth routes)

 const router = require("express").Router();
const passport = require("passport");
const cors = require("cors");
const CLIENT_HOME_PAGE_URL = "http://localhost:3000";

/Route is api/auth/test
router.get("/test", function (req, res) {
  res.send(console.log("Test to backend"));
});


//Route is api/auth/auth/google/callback
router.get(
  "/auth/google/callback",
  passport.authenticate("google", {
    successRedirect: CLIENT_HOME_PAGE_URL,
    failureRedirect: "/",
    session: false,
  }),
  function (req, res) {
    var token = req.user.token;
    res.redirect("http://localhost:3000?token="   token);
  }
);


  //Route is api/auth/auth/google/
router.get(
  "/auth/google",

  passport.authenticate("google", { scope: ["profile", "email"] })
);

module.exports = router;
 

Passport.js

 var passport = require("passport");
var GoogleStrategy = require("passport-google-oauth").OAuth2Strategy;

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

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

passport.use(
  new GoogleStrategy(
    {
      clientID:
        "*****",
      clientSecret: "*****",
      callbackURL: "http://localhost:3001/api/auth/auth/google/callback",
    },
    function (accessToken, refreshToken, profile, done) {
      var userData = {
        email: profile.emails[0].value,
        name: profile.displayName,
        token: accessToken,
      };
      done(null, userData);
    }
  )
);
 

Я знаю, что это немного длинный пост, если у кого-то есть какие-либо идеи или решения, которые мне очень помогут.

Ответ №1:

Недавно я столкнулся с той же проблемой. С помощью

 window.location.href = "http://localhost:5000/api/auth/google" 
 

вместо

 axios.get("/api/auth/auth/google") 
 

решил проблему.

При успешной аутентификации, если вы хотите перенаправить пользователя на исходный URL-адрес, по которому пользователь сделал запрос на вход, вы можете это сделать…

 const currentUrl = window.location.href
const encodedParam = encodeURI(`?redirectUrl=${currentUrl}`)
window.location.href = `http://localhost:5000/api/auth/google${encodedParam}`
 

Сохраните значение перенаправления в сеансе

 req.session.redirectPath = req.query.redirectUrl
 

и после аутентификации используйте это в своем маршруте обратного вызова