簡體   English   中英

Passport.js、會話和反應 | 從 /login 路由以外的任何路由訪問 req.user 是未定義的

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

我在 localhost:3000 有一個 React 客戶端設置,在 localhost:5000 有一個 node.js 服務器

我正在嘗試一個簡單的身份驗證流程,其中客戶端嘗試使用 Passport.js Google OAuth2.0 對服務器進行身份驗證,並使用 MongoDB 商店的快速會話保持身份驗證。

我相信我發現 req.user 未定義的原因是因為我對身份驗證流程應該如何工作以及實際代碼的任何問題缺乏了解。

我正在通過 react 客戶端中的以下代碼啟動身份驗證流程:

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

以下是我的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;

以下是我的谷歌策略配置:

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));
    });
};

以下代碼是我的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}`));

用戶登錄后,我通過其中一條路由從數據庫中獲取帖子:

...
// @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);
    });
});

我假設在用戶被重定向到儀表板然后向路由發送請求以獲取所有帖子后,用戶未通過身份驗證? 雖然我在驗證用戶身份后將用戶重定向到這條路線?

目標絕對不是在 /posts 路由中獲取用戶,而是創建一個單獨的 /user 路由,將用戶返回到客戶端,但這也會導致 req.user 未定義。

終於讓它工作了。

我不得不編輯兩件事,

首先(服務器端):

我必須設置 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
   })
);

第二(客戶端):

我不得不讓 Axios 知道它必須將 cookie 與請求一起發送,如下所示:

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

其中/auth/user路由定義如下:

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

如果我對整個身份驗證過程有更好的了解,這些錯誤是可以避免的,現在我做到了。

我們生活,我們學習。

起初haidousm的回答對我不起作用,我所做的就是在我的登錄請求中添加了{ withCredentials: true }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM