Javascript Passport.js、会话和;React |未定义从除/login路由以外的任何路由访问req.user

Javascript Passport.js、会话和;React |未定义从除/login路由以外的任何路由访问req.user,javascript,node.js,reactjs,express,passport.js,Javascript,Node.js,Reactjs,Express,Passport.js,我在localhost:3000有一个React客户端设置,在localhost:5000有一个node.js服务器 我正在尝试一个简单的身份验证流,其中客户端尝试使用Passport.js Google OAuth2.0与服务器进行身份验证,并使用与MongoDB存储区的express会话保持身份验证 我认为我之所以发现req.user是未定义的,是因为我不了解auth流应该如何工作,而不是实际代码中的任何问题 我正在通过react客户端中的以下代码启动身份验证流: <Button hr

我在localhost:3000有一个React客户端设置,在localhost:5000有一个node.js服务器

我正在尝试一个简单的身份验证流,其中客户端尝试使用Passport.js Google OAuth2.0与服务器进行身份验证,并使用与MongoDB存储区的express会话保持身份验证

我认为我之所以发现req.user是未定义的,是因为我不了解auth流应该如何工作,而不是实际代码中的任何问题

我正在通过react客户端中的以下代码启动身份验证流:

<Button href="http://localhost:5000/auth/google">
        Login using Google
</Button>
以下是我的谷歌战略配置:

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}`));
在用户登录后,我通过以下路径之一从DB获取帖子:

...
// @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);
    });
});
。。。
//@desc获取所有帖子
//@route-GET/posts
路由器.get(“/”,(请求,res)=>{
const posts=Post.find(函数(错误,posts){
if(error)返回控制台。error(error);

console.log(req.user)/终于让它工作了

我必须编辑两件事

第一(服务器端):

我必须设置CORS以允许Cookie通过:

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);
    }
});
如果我对整个身份验证过程有了更好的了解,这些错误本来是可以避免的,现在我确实了解了


我们生活,我们学习。

终于让它发挥作用了

我必须编辑两件事

第一(服务器端):

我必须设置CORS以允许Cookie通过:

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);
    }
});
如果我对整个身份验证过程有了更好的了解,这些错误本来是可以避免的,现在我确实了解了


我们生活,我们学习。

我想你只是缺少了
/
获取
路由的passport身份验证中间件。如果你想在默认情况下将中间件应用于所有路由,你可以使用
应用程序。使用(…)
@PascalLamers我不确定这是哪个中间件?如果值得一提的话,直接通过浏览器访问
/GET
路由(通过访问localhost:5000/posts),它会成功记录用户,但如果通过客户端访问,则不会。我打赌客户端没有经过身份验证,但我不确定该怎么办?可能是这样的,所以身份验证通过:5000进行。下面是Facebook身份验证流的示例(类似)…他们没有使用完整的URL进行回调。你可以试试,或者在回调中使用:3000?我尝试过在回调中使用路由,而不是完整的URL。不幸的是,这不起作用。我不确定回调中是否使用:3000,因为回调必须通过服务器@端口5000。谢谢你的示例。唯一的不同之处在于,他们是通过服务器呈现页面,而不是按照我的方式设置客户端服务器。啊,我想我记得我在客户端呈现的站点中使用passport时遇到了类似的问题。一个好主意是为端口使用环境变量(开发与生产)这样你就不需要一直更改它。我做的另一件事是在回调控制器中,用accessToken作为查询参数重定向到前端,这样我就可以访问它和客户端应用程序。但是我在做事情时使用了一种非基于cookie的方法。你使用Google只是为了验证用户,还是使用Google你打算代表用户使用Google API吗?我想你只是缺少了
/
GET
路由的passport身份验证中间件。如果你想在默认情况下将中间件应用于所有路由,你可以使用
应用程序。使用(…)
@PascalLamers我不确定这是哪个中间件?如果值得一提的话,直接通过浏览器访问
/GET
路由(通过访问localhost:5000/posts),它会成功记录用户,但如果通过客户端访问,则不会。我打赌客户端没有经过身份验证,但我不确定该怎么办?可能是这样的,所以身份验证通过:5000进行。下面是Facebook身份验证流的示例(类似)…他们没有使用完整的URL进行回调。你可以试试,或者在回调中使用:3000?我尝试过在回调中使用路由,而不是完整的URL。不幸的是,这不起作用。我不确定回调中是否使用:3000,因为回调必须通过服务器@端口5000。谢谢你的示例。唯一的不同之处在于,他们是通过服务器呈现页面,而不是按照我的方式设置客户端服务器。啊,我想我记得我在客户端呈现的站点中使用passport时遇到了类似的问题。一个好主意是为端口使用环境变量(开发与生产)这样你就不需要一直更改它。我做的另一件事是在回调控制器中,用accessToken作为查询参数重定向到前端,这样我就可以访问它和客户端应用程序。但是我在做事情时使用了一种非基于cookie的方法。你使用Google只是为了验证用户,还是使用Google你打算代表用户使用谷歌API吗?谢谢你发布答案,你为我节省了很多时间。谢谢你发布答案,你为我节省了很多时间。