Node.js+Passport Google登录:req.user.firstName读取未定义错误求助
求助:TypeError: Cannot read properties of undefined (reading 'firstName')
我已经尝试解决这个问题好几天了,现在向社区求助。跟着教程开发时,我遇到了如下错误:尝试获取req.user.firstName值时,抛出TypeError: Cannot read properties of undefined (reading 'firstName')。目前我能正常渲染dashboard页面,但无法显示firstName值,不确定问题出在哪,以下是相关代码:
App.js 文件
const path = require("path"); const express = require("express"); const dotenv = require("dotenv"); const mongoose = require("mongoose"); const morgan = require("morgan"); const exphbs = require("express-handlebars"); const connectDB = require("./config/db"); const passport = require("passport"); const session = require("express-session"); const MongoStore = require("connect-mongo"); const routes = require("./routes/index"); const authent = require("./routes/auth"); const bodyParser = require("body-parser"); const cookieSession = require("cookie-session"); //Loading the config dotenv.config({ path: "./config/config.env" }); //Passport config require("./config/passport")(passport); //Coonecting to DB connectDB(); const app = express(); app.use(express.json()); // Body parser app.use(express.urlencoded({ extended: false })); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); //Morgan if (process.env.NODE_ENV === "development") { app.use(morgan("dev")); } //Handlebars app.engine(".hbs", exphbs.engine({ defaultLayout: "main", extname: ".hbs" })); app.set("view engine", ".hbs"); //Session middleware app.use( session({ secret: "the secret", resave: false, saveUninitialized: false, // cookie: { secure: true }, store: MongoStore.create({ mongoUrl: process.env.MONGO_URI }), }) ); //Passport middleware app.use(passport.initialize()); app.use(passport.session()); //Static folder app.use(express.static(path.join(__dirname, "public"))); //Routes app.use("/", routes); app.use("/auth", authent); const PORT = process.env.PORT || 3000; app.listen( PORT, console.log( `The server is running IN ${process.env.NODE_ENV} mode, on port ${PORT}` ) );
Index.js 文件
const express = require("express"); const router = express.Router(); const { ensureAuth, ensureGuest } = require("../middleware/auth"); //Description Login/Landing page //@route GET / router.get("/", ensureGuest, function (req, res) { res.render("login", { layout: "login", }); }); //Description Dashboard page //@route GET /dashboard router.get("/dashboard", ensureAuth, function (req, res) { res.render("dashboard", { name: req.user.firstName, }); }); module.exports = router;
User 模型文件
const mongoose = require("mongoose"); const UserSchema = new mongoose.Schema({ googleId: { type: String, // required: true, }, displayName: { type: String, required: true, }, firstName: { type: String, required: true, }, familyName: { type: String, required: true, }, image: { type: String, }, createdAt: { type: Date, default: Date.now, }, }); module.exports = mongoose.model("User", UserSchema);
Passport.js 文件
const GoogleStrategy = require("passport-google-oauth20").Strategy; const mongoose = require("mongoose"); const User = require("../models/User"); require("https").globalAgent.options.rejectUnauthorized = false; module.exports = function (passport) { passport.use( new GoogleStrategy( { clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: "http://localhost:3000/auth/google/callback", }, async (accessToken, refreshToken, profile, done) => { console.log(profile); const newUser = { googleId: profile.id, displayName: profile.displayName, firstName: profile.name.givenName, familyName: 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, newUser); } } catch (error) { console.log(error); } } ) ); passport.serializeUser(function (user, done) { done(null, user.id); }); passport.deserializeUser(function (user, done) { User.findById(user.id, function (error, user) { done(error, user); }); }); };
问题排查与修复
核心问题是req.user未被正确初始化,导致读取firstName时出错,以下是具体修复步骤:
1. 修正Passport策略的回调返回值
在创建新用户后,你传递给done的是自己构建的newUser普通对象,而非Mongoose返回的文档实例,这会导致序列化/反序列化流程异常。修改为:
// 原代码 user = await User.create(newUser); done(null, newUser); // 修改后 user = await User.create(newUser); done(null, user);
2. 解决反序列化函数的参数命名冲突
deserializeUser中参数名与回调内变量名重复,导致作用域混淆,修改参数名避免冲突:
// 原代码 passport.deserializeUser(function (user, done) { User.findById(user.id, function (error, user) { done(error, user); }); }); // 修改后 passport.deserializeUser(function (userId, done) { User.findById(userId, function (error, user) { done(error, user); }); });
3. 验证ensureAuth中间件逻辑
确保ensureAuth中间件正确拦截未认证请求,示例实现如下:
module.exports.ensureAuth = (req, res, next) => { if (req.isAuthenticated()) { return next(); } res.redirect('/'); };
若中间件逻辑错误,会让未认证请求进入dashboard路由,此时req.user为undefined。
4. 清除旧Session数据
之前的错误可能导致MongoDB的session集合存储了无效用户ID,建议清除该集合的旧数据后重启服务,重新登录测试。
内容的提问来源于stack exchange,提问作者Will.Nasib
相关产品推荐
相关产品推荐

