使用Passport.js+AJAX注册用户时会话序列化失败错误如何解决
错误触发根本原因
- 路由验证逻辑存在缺陷:当Passport本地策略验证不通过(如邮箱已被注册)时,返回的
user值为false,代码未做拦截直接将false传入req.login()方法,序列化用户时尝试读取不存在的user.id属性,直接触发序列化失败报错。 - 存在潜在代码问题:
local.popsignup策略中给新用户赋值newUser.preferences = preferences时,preferences变量未声明定义,可能引发额外报错。
修复步骤
1. 调整路由逻辑,拦截验证失败场景
仅当验证通过、拿到有效用户对象时才执行登录逻辑,代码修改如下:
module.exports = (app, passport) => { app.post('/popover', function(req, res, next) { passport.authenticate('local.popsignup', function(err, user, info) { // 优先捕获系统级错误 if (err) return next(err); // 验证不通过直接返回结果,不执行登录流程 if (!user) { const errors = req.flash('error'); return res.status(200).send({errors: errors, loggedIn: false}); } // 仅验证通过时执行登录 req.login(user, function(err) { if (err) return next(err); res.status(200).send({errors: [], loggedIn: true}); }); })(req, res, next); }); }
2. 修复策略中未定义变量问题
从请求中获取preferences参数,确保变量定义合法:
passport.use('local.popsignup', new LocalStrategy({ usernameField: 'popUsername', passwordField: 'popPassword', passReqToCallback: true }, (req, email, password, done) => { User.findOne({'email':email}, (err, user) => { if(err){ return done(err); } if(user){ return done(null, false, req.flash('error', 'Email already exists, please login.')) } // 新增:从请求中获取preferences参数,避免变量未定义 const preferences = req.body.preferences || {}; var newUser = new User(); newUser.email = email; newUser.password = newUser.encryptPassword(password); newUser.preferences = preferences; // 新增:捕获存储错误避免静默失败 newUser.save((err) => { if (err) return done(err); return done(null, newUser); }); }); }));
3. 前端表单补全参数
在弹窗的注册表单#popform-tag中添加隐藏域存储preferences参数,保证serialize()方法能正常提交该字段到服务端。
内容的提问来源于stack exchange,提问作者alabaster
相关产品推荐
相关产品推荐

