You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 05:57:21