Express-session+Passport每次请求创建会话,如何仅登录后生成?
我正在开发电商平台前后端,使用Express和Passport实现登录注册系统。当前遇到的问题是:每次访问站点中带请求的页面,都会创建新会话并存入MongoDB,比如浏览3个页面就会生成3条不同的会话记录。我的需求是仅在用户登录后才创建会话。
已经尝试过在Axios请求中启用withCredentials,也设置过saveUninitialized,但都无效。推测是Passport会向Cookie插入空对象,导致会话被标记为已修改,进而触发存储。
原因分析
Passport的passport.session()中间件会在每个请求中尝试反序列化用户。如果用户未登录,req.user会被设为null,这个操作会修改req.session对象(添加passport: {}空字段)。即使设置了saveUninitialized: false,只要会话对象被修改,express-session就会认为会话已初始化,从而将其存入MongoDB。另外原代码中saveUnitialized存在拼写错误,正确应为saveUninitialized,这也导致该配置未生效。
解决方案
核心思路是仅在用户登录成功后才启用Passport会话处理,避免未登录请求触发会话修改和存储。具体步骤如下:
给Passport会话中间件添加条件判断
不全局启用passport.session(),而是自定义中间件,仅当会话中已有用户信息时才执行Passport的会话逻辑,未登录请求直接跳过。修复
saveUninitialized拼写错误
修正session配置中的拼写错误,确保saveUninitialized: false生效,阻止未初始化的会话被存储。调整
resave配置(可选)
将resave设为false,减少不必要的会话存储操作,提升性能。
修改后的关键代码
app.js 核心修改
// 替换原有的app.use(passport.session()) // 自定义中间件:仅已登录用户启用Passport会话处理 app.use((req, res, next) => { if (req.session?.user) { return passport.session()(req, res, next); } next(); }); // 修复session配置的拼写错误及优化参数 app.use(session({ store: MongoStore.create({ mongoUrl: 'blablabla', mongoOptions: {useNewUrlParser: true, useUnifiedTopology: true}, ttl: 15 }), cookie:{ maxAge: 7 * 24 * 60 * 60 * 1000, }, secret: 'mysecret', resave: false, saveUninitialized: false // 修正拼写错误 }))
可选:优化反序列化逻辑
避免未登录时触发不必要的数据库查询:
// passport.config.js 中修改deserializeUser passport.deserializeUser(async(id, done)=>{ try { const user = await userModel.findById(id); done(null, user); } catch (err) { done(err, null); } })
验证效果
修改完成后,未登录状态下访问页面或接口,MongoDB不会生成新会话记录;只有当用户完成登录或注册操作后,系统才会创建并存储会话,符合需求。
内容的提问来源于stack exchange,提问作者Ramiro Silva

