Passport-Local报错:Expected a `length`需为非负有限数求助
解决passport-local认证时"Expected a
length to be a non-negative finite number"错误 这个错误的核心原因是passport-local默认从req.body.username获取用户名,但你的注册请求参数里只有email,没有username字段,导致认证时用户名是undefined,内部逻辑尝试读取它的length属性时抛出错误。另外,你在注册成功后调用passport.authenticate其实是多余的操作,这也可以简化掉。
方案1:调整passport-local-mongoose配置匹配你的字段
你的AccountModel用username字段存储邮箱,而passport-local默认期望从req.body.username取用户名,但你的请求传的是email。可以通过两种方式对齐:
方式A:让插件使用email作为用户名字段(更规范)
修改你的AccountModel,把存储邮箱的字段名改为email,并配置插件指定用户名字段:
import mongoose from 'mongoose'; import passportLocalMongoose from 'passport-local-mongoose'; const Schema = mongoose.Schema; let Account = new Schema ({ active: { type: Boolean, default: false }, displayName: { type: String, default: "Uknown" }, verificationToken: { type: String, default: "" }, profileImageUrl: { type: String, default: "" }, profileImagePubid: { type: String, default: "" }, likes: [{ type: Schema.Types.ObjectId, ref: "Spot" }], nation: { type: String, default: "ND" }, points: { type: Number, default: 0 }, email: { type: String, required: true, unique: true } // 改为email字段 }); // 指定用email作为用户名字段 Account.plugin(passportLocalMongoose, { usernameField: 'email' }); module.exports = mongoose.model('Account', Account);
然后在注册接口里,把newUser的email设为请求的email:
let newUser = new AccountModel({ email: req.body.email, verificationToken: "", active: false, displayName: "Uknown", profileImageUrl: "", profileImagePubid: "", likes: [], nation: req.body.nation, points: 0 });
方式B:临时给req.body添加username字段
如果不想修改模型结构,可以在调用passport.authenticate前手动把req.body.username设为req.body.email:
AccountModel.register(newUser, req.body.password, function(err, account) { if(err){ writeLog("ERROR", req.url + " - Error: -1 " + err.message); res.status(500).send( { error: err.message, errnum: -1 } ); return; } // 添加这行,让passport能获取到正确的用户名 req.body.username = req.body.email; passport.authenticate('local', { session: false })(req, res, (err) => { if(err){ writeLog("ERROR",req.url + " - Error: -2 " + err.message); res.status(500).send( { error: err.message, errnum: -2 } ); return; } // 后续逻辑 }); });
方案2:移除多余的passport.authenticate调用
其实AccountModel.register方法已经完成了用户创建和密码哈希操作,你完全没必要再调用认证——你刚创建的用户肯定是有效的。直接跳过认证步骤,直接处理验证token的生成和保存:
AccountModel.register(newUser, req.body.password, function(err, account) { if(err){ writeLog("ERROR", req.url + " - Error: -1 " + err.message); res.status(500).send( { error: err.message, errnum: -1 } ); return; } // 直接跳过authenticate,处理后续逻辑 var strVer = crypto(16); account.verificationToken = strVer; account.active = false; account.save( (err, account) => { if(err) { writeLog("ERROR",req.url + " - Error: -3 " + err.message); res.status(500).send( { error: err.message, errnum: -3 } ); return; } // 发送邮件等逻辑 var dataToSend = { "user_email": account.username, "verification_token": strVer }; sendEmailSendgrid(account.username, process.env.SENDGRID_TEMPLATE_VER_EMAIL, "Confirm your email address please!", dataToSend); writeLog("INFO",req.url + " - Successfully created new account - " + account.username); res.status(200).send( { message : "Successfully created new account", token: strVer } ); return; }); });
这种方式既简化了代码,又彻底避免了认证阶段的错误。
内容的提问来源于stack exchange,提问作者Oscar TJ
相关产品推荐
相关产品推荐

