通过 Passport.js 与第 3 方(discord)在 React 上进行身份验证在本地工作,但在托管在 Heroku 上时不起作用

Authentication through Passport.js with 3rd-party (discord) on React works locally but not when hosted on Heroku

我一直在尝试使用 Passportjs 通过 discord 实现登录并设法让它在本地工作(部分地,我在处理回调后的重定向时遇到问题,所以现在我手动将自己路由回着陆页@“/”),成功重定向到 https://discordapp.com/oauth2/authorize... 等等。然而,当托管在 Heroku 上时,它不再有效地址栏显示正确的“/auth/discord”地址,但只显示空白页面。

我试过使用来自 react-router-bootstrap 的 LinkContainers,使用来自 react-bootstrap 的 Nav.Item 和 Nav.Link,打开和关闭 CORS,重新排列服务器端路由顺序,仅使用锚标记,调整身份验证请求的范围以及我现在不记得的其他几件事。虽然似乎没有什么不同。我一定是找错树了。

对于我应该查看的内容的任何提示,我将不胜感激。请在下面找到我的代码:

App.js

import React, { useEffect } from "react";
import { Switch, Route } from "react-router-dom";
import { connect } from "react-redux";

import { checkUserSession } from "./redux/user/user.actions";

import Header from "./components/header/header.component";
const Landing = () => <h2>Landing</h2>;
const FrontTest = () => <h2>FrontTest</h2>;

const App = ({ checkUserSession, currentUser }) => {
  useEffect(() => {
    checkUserSession();
  }, [checkUserSession]);

  return (
    <div>
      <Header />
      <Switch>
        <Route exact path="/" component={Landing} />
        <Route exact path="/fronttest" component={FrontTest} />
      </Switch>
    </div>
  );
};

const mapStateToProps = ({ user: { currentUser } }) => ({
  currentUser,
});

const mapDispatchToProps = (dispatch) => ({
  checkUserSession: () => dispatch(checkUserSession()),
});

export default connect(mapStateToProps, mapDispatchToProps)(App);

header.component.jsx

import React from "react";
import { connect } from "react-redux";

import Navbar from "react-bootstrap/Navbar";
import Nav from "react-bootstrap/Nav";
import Button from "react-bootstrap/Button";

import DiscordSignin from "../discord-signin/discord-signin.component";

import { signOutStart } from "../../redux/user/user.actions";

const Header = ({ currentUser, signOutStart }) => (
  <Navbar bg="dark" variant="dark" fixed="sticky-top" expand="sm">
    <Navbar.Brand href="/">Race League</Navbar.Brand>
    <Navbar.Toggle aria-controls="basic-navbar-nav" />
    <Navbar.Collapse id="basic-navbar-nav">
      <Nav className="mr-auto">
        <Nav.Link href="/fronttest">FrontTest</Nav.Link>
      </Nav>
      {currentUser ? (
        <Button onClick={signOutStart} variant="outline-danger">
          Sign out
        </Button>
      ) : (
        <Nav.Link href="/auth/discord">
          <DiscordSignin />
        </Nav.Link>
      )}
    </Navbar.Collapse>
  </Navbar>
);

const mapStateToProps = ({ user: { currentUser } }) => ({
  currentUser,
});

const mapDispatchToProps = (dispatch) => ({
  signOutStart: () => dispatch(signOutStart()),
});

export default connect(mapStateToProps, mapDispatchToProps)(Header);

server.js

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const path = require("path");
const compression = require("compression");
const enforce = require("express-sslify");

const passport = require("passport");

if (process.env.NODE_ENV !== "production") require("dotenv").config();

require("./models/User");
require("./services/passport");

const app = express();
const PORT = process.env.PORT || 5000;

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());

app.use(cors());

app.use(passport.initialize());

require("./routes/authRoutes")(app);

if (process.env.NODE_ENV === "production") {
  app.use(compression());
  app.use(enforce.HTTPS({ trustProtoHeader: true }));
  app.use(express.static(path.join(__dirname, "client/build")));

  app.get("*", (req, res) => {
    res.sendFile(path.join(__dirname, "client/build", "index.html"));
  });
}

app.listen(PORT, (error) => {
  if (error) throw error;
  console.log("Server running on port " + PORT);
});

authRoutes.js

const passport = require("passport");
const jwt = require("jsonwebtoken");

module.exports = app => {
  app.get("/auth/discord", passport.authenticate("discord"));

  app.get("/auth/discord/callback", (req, res) => {
    passport.authenticate(
      "discord",
      {
        failureRedirect: "/",
        session: false
      },
      (error, user) => {
        if (error || !user) {
          res.status(400).json({ error });
        }

        // jwt content
        const payload = {
          ...user,
          expires: Date.now() + 30 * 24 * 60 * 60 * 1000
        };

        // assign payload to req.user
        req.login(payload, { session: false }, error => {
          if (error) {
            res.status(400).send({ error });
          }

          // generate a signed json web token and return it in the response
          const token = jwt.sign(JSON.stringify(payload), process.env.JWT_KEY);
          const cookieOption =
            process.env.NODE_ENV === "production" ? { secure: true } : {};
          // assign jwt to cookie
          res.cookie("jwt", token, cookieOption);
          res.redirect("/");
        });
      }
    )(req, res);
  });

  app.get(
    "/api/current_user",
    passport.authenticate("jwt", { session: false }),
    (req, res) => {
      const { user } = req;
      res.status(200).send({ user });
    }
  );
};

所以,在尝试了很多东西之后,我决定创建一个新的 heroku 应用程序并上传相同的代码。它奏效了!仍然不知道出了什么问题,因为我从未编辑过构建包等...

发布这个只是为了让其他人比我更早地尝试这个。