简体   繁体   English

Passport.js、会话和反应 | 从 /login 路由以外的任何路由访问 req.user 是未定义的

[英]Passport.js, Sessions, & React | Accessing req.user from any route other than the /login route is undefined

I have a React client setup at localhost:3000 and a node.js server at localhost:5000我在 localhost:3000 有一个 React 客户端设置,在 localhost:5000 有一个 node.js 服务器

I'm trying a simple auth flow in which the client tries to authenticate with the server using Passport.js Google OAuth2.0 and staying authenticated using express-sessions with a MongoDB store.我正在尝试一个简单的身份验证流程,其中客户端尝试使用 Passport.js Google OAuth2.0 对服务器进行身份验证,并使用 MongoDB 商店的快速会话保持身份验证。

I believe the reason I'm finding req.user is undefined is because of my lack of understanding of how the auth flow is supposed to work versus any issues with the actual code.我相信我发现 req.user 未定义的原因是因为我对身份验证流程应该如何工作以及实际代码的任何问题缺乏了解。

I'm initiating the auth flow through the following code in the react client:我正在通过 react 客户端中的以下代码启动身份验证流程:

<Button href="http://localhost:5000/auth/google">
        Login using Google
</Button>

The following is my auth.js file:以下是我的auth.js文件:

const express = require("express");
const passport = require("passport");
const router = express.Router();

// @desc    Auth with Google
// @route   GET /auth/google
router.get("/google", passport.authenticate("google", { scope: ["profile"] }));

// @desc    Google auth callback
// @route   GET /auth/google/callback
router.get(
    "/google/callback",
    passport.authenticate("google", {
        failureRedirect: "/",
        successRedirect: "http://localhost:3000/dashboard",
    })
);

// @desc    Logout user
// @route   /auth/logout
router.get("/logout", (req, res) => {
    req.logout();
    res.redirect("/");
});

module.exports = router;

The following is my Google Strategy configuration:以下是我的谷歌策略配置:

const GoogleStrategy = require("passport-google-oauth20").Strategy;
const mongoose = require("mongoose");
const User = require("../models/User");

module.exports = function (passport) {
    passport.use(
        new GoogleStrategy(
            {
                clientID: process.env.GOOGLE_CLIENT_ID,
                clientSecret: process.env.GOOGLE_CLIENT_SECRET,
                callbackURL: "http://localhost:5000/auth/google/callback",
            },
            async (accessToken, refreshToken, profile, done) => {
                const newUser = {
                    googleId: profile.id,
                    displayName: profile.displayName,
                    firstName: profile.name.givenName,
                    lastName: profile.name.familyName,
                    image: profile.photos[0].value,
                };

                try {
                    let user = await User.findOne({ googleId: profile.id });

                    if (user) {
                        done(null, user);
                    } else {
                        user = await User.create(newUser);
                        done(null, user);
                    }
                } catch (err) {
                    console.error(err);
                }
            }
        )
    );

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

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

The following code is my index.js which brings everything together:以下代码是我的index.js ,它将所有内容组合在一起:

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const connectDB = require("./config/db");
const morgan = require("morgan");
const passport = require("passport");
const session = require("express-session");
const MongoStore = require("connect-mongo")(session);

// Dotenv config
const dotenv = require("dotenv").config({
    path: "./config/config.env",
});

// Passport config
require("./config/passport")(passport);

// MongoDB config
connectDB();

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

// Middleware

app.use(cors());
app.use(bodyParser.json());
app.use(morgan("dev"));

// Sessions
app.use(
    session({
        secret: "stackoverflow",
        resave: false,
        saveUninitialized: false,
        store: new MongoStore({ mongooseConnection: mongoose.connection }),
    })
);

// Passport middleware
app.use(passport.initialize());
app.use(passport.session());

app.use("/posts", require("./routes/posts"));
app.use("/auth", require("./routes/auth"));

app.listen(PORT, () => console.log(`Server listening @ port ${PORT}`));

I am fetching posts from the DB through one of the routes after user login:用户登录后,我通过其中一条路由从数据库中获取帖子:

...
// @desc Get all posts
// @route GET /posts

router.get("/", (req, res) => {
    const posts = Post.find(function (error, posts) {
        if (error) return console.error(error);
        console.log(req.user) // <------ is undefined
        res.json(posts);
    });
});

I'm assuming that after the user is being redirected to the dashboard and then sending a request to the route to get all posts, the user is not authenticated?我假设在用户被重定向到仪表板然后向路由发送请求以获取所有帖子后,用户未通过身份验证? Although I redirected the user towards this route after authenticating him?虽然我在验证用户身份后将用户重定向到这条路线?

The goal is definitely not to fetch the user at the /posts route but create a separate /user route that returns the user to the client, but that also results in req.user being undefined.目标绝对不是在 /posts 路由中获取用户,而是创建一个单独的 /user 路由,将用户返回到客户端,但这也会导致 req.user 未定义。

Finally got it to work.终于让它工作了。

I had to edit two things,我不得不编辑两件事,

First (Server Side):首先(服务器端):

I had to setup CORS to allow cookies to pass through as such:我必须设置 CORS 以允许 cookies 这样通过:

app.use(
    cors({
         origin: "http://localhost:3000", // allow to server to accept request from different origin
         methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
         credentials: true, // allow session cookie from browser to pass through
   })
);

Second (Client Side):第二(客户端):

I had to let Axios know that it has to send the cookie alongside the request as such:我不得不让 Axios 知道它必须将 cookie 与请求一起发送,如下所示:

axios
     .get("http://localhost:5000/auth/user", { withCredentials: true })
     .then(console.log)
     .catch(console.error);

where the /auth/user route is defined as such:其中/auth/user路由定义如下:

router.get("/user", (req, res) => {
    if (req.user) {
        res.json(req.user);
    }
});

These mistakes could have been avoided had I had a better understanding of the entire authentication process, of which now I do.如果我对整个身份验证过程有更好的了解,这些错误是可以避免的,现在我做到了。

We live and we learn.我们生活,我们学习。

At first haidousm's answer did not work for me, what I did was I added { withCredentials: true } to the post request for my login as well.起初haidousm的回答对我不起作用,我所做的就是在我的登录请求中添加了{ withCredentials: true }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM