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

Express+Passport谷歌登录后req.user丢失,会话检查报错排查

问题描述

搭建NodeJS & Express应用,使用Passport实现谷歌登录认证:

  • 本地环境登录流程正常,登录后能看到req.user包含完整用户信息
  • 后续调用任意路由时req.user变为undefined
  • 尝试添加登录检查中间件重定向到登录页,出现ECONNRESET错误

相关代码

const express = require("express");
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const app = express()
const port = 5000

// if user is not logged-in redirect back to login page
app.use(function(req, res, next) {
   if (req.session.user == null){
   res.redirect('http://localhost:3000/login');
   }   else {
    next();
   }
});

app.use(
  session({
  secret: 'keyboard cat',
  resave: false,
  cookie: { httpOnly: false, secure: false, maxAge: 60 * 1000},
  saveUninitialized: false,
     })
  )

passport.use(
  new GoogleStrategy({
  clientID: "process.env.clientID",
  clientSecret: "process.env.clientSecret",
  callbackURL: '/auth/google/callback',
},
async (accessToken, refreshToken, profile, done) => {
  const existingUser = await User.findOne({
    providerId: profile.id,
  })
  if (existingUser) {
      return done(null, existingUser);
  }
  const user = await new User({
    provider: profile.provider,
    providerId: profile.id,
    displayName: profile.displayName,
    
  }).save()
  done(null, user);
 })
)

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

passport.deserializeUser(function (obj, done) {
  done(null, done);
});

报错信息

ERROR  Error in fetch(): request to http://localhost:3000/login failed, reason: read ECONNRESET

  at ClientRequest.<anonymous> (node_modules/node-fetch/lib/index.js:1461:11)
  at ClientRequest.emit (events.js:400:28)
  at Socket.socketErrorListener (_http_client.js:475:9)
  at Socket.emit (events.js:400:28)
  at emitErrorNT (internal/streams/destroy.js:106:8)
  at emitErrorCloseNT (internal/streams/destroy.js:74:3)
  at processTicksAndRejections (internal/process/task_queues.js:82:21)
修复方案

1. 修正中间件加载顺序

Express中间件按执行顺序加载,登录检查逻辑必须放在session和Passport初始化之后,同时要排除登录相关路由避免无限重定向:

// 先加载session中间件
app.use(
  session({
    secret: 'keyboard cat',
    resave: false,
    cookie: { httpOnly: true, secure: false, maxAge: 60 * 1000}, // 建议开启httpOnly提升安全性
    saveUninitialized: false,
  })
)

// 初始化Passport
app.use(passport.initialize());
app.use(passport.session()); // 必须在session中间件之后加载

// 登录检查中间件:跳过登录授权及回调路由
app.use(function(req, res, next) {
  const authRoutes = ['/auth/google', '/auth/google/callback'];
  if (authRoutes.includes(req.path)) {
    return next();
  }
  // Passport将用户信息存在req.user而非req.session.user
  if (!req.user) {
    return res.redirect('http://localhost:3000/login');
  }
  next();
});

2. 修复deserializeUser逻辑

当前代码错误地将done函数作为用户对象返回,需根据序列化的user.id查询用户并返回:

passport.deserializeUser(async function (userId, done) {
  try {
    const user = await User.findById(userId);
    done(null, user);
  } catch (err) {
    done(err, null);
  }
});

3. 正确读取环境变量

不要用字符串包裹process.env变量,否则会读取到字面量字符串而非实际环境变量:

passport.use(
  new GoogleStrategy({
    clientID: process.env.clientID, // 去掉引号
    clientSecret: process.env.clientSecret, // 去掉引号
    callbackURL: '/auth/google/callback',
  },
  // 其余逻辑保持不变
  )
)

4. 解决ECONNRESET错误

该错误通常由以下原因导致:

  • 前端localhost:3000服务未启动,后端重定向请求失败
  • 登录检查中间件未排除登录路由,导致无限重定向触发连接重置
    按步骤1修复中间件后,确保前端服务正常运行即可解决。

内容的提问来源于stack exchange,提问作者Thestrike95

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:05:36