在NodeJS中重置密码

我做了一个设置,使用NodeJS /护照更新用户的密码。 我遵循这个伟大的指南: http : //sahatyalkabov.com/how-to-implement-password-reset-in-nodejs/ 。

这99%的工作。 我不得不修改它包含一些条纹function。 但是我担心我有一个严重的错误,我无法find它。 用户现在可以通过发送电子邮件的过程,input一个新的密码,并login。另一封电子邮件说,他们的密码已成功更新。 全部完美。 然而。 因为某些原因。 新密码没有被保存。 用户只能使用旧密码login。 我已经尝试了所有我能想到的方法来解决这个问题。

我还有其他几个程序员看这个,他们中没有一个能够弄清楚它在世界上是如何工作的。

目前的想法是,会议可能没有正确结束,但我们试图破坏会议,它仍然没有工作。

任何帮助不胜感激。

完整设置:

用户模式:

var UserSchema = new mongoose.Schema({ username: { type: String, required: true, unique: true }, password: String, datapoint: String, email: { type: String, required: true, unique: true }, resetPasswordToken: String, resetPasswordExpires: Date }); UserSchema.pre('save', function(next) { var user = this; var SALT_FACTOR = 5; if (!user.isModified('password')) return next(); bcrypt.genSalt(SALT_FACTOR, function(err, salt) { if (err) return next(err); bcrypt.hash(user.password, salt, null, function(err, hash) { if (err) return next(err); user.password = hash; next(); }); }); }); 

注册新帐户 (这也有条纹信息无关,但可能导致问题。)

 var newUser = new User({username: req.body.username, email: req.body.email, datapoint: req.body.datapoint}); User.register(newUser, req.body.password, function(err, user){ if(err){ console.log('Looks like there was an error:' + ' ' + err) res.redirect('/login') } else { passport.authenticate("local")(req, res, function(){ var user = new User({ username: req.body.username, email: req.body.email, password: req.body.password }) console.log('creating new account') console.log('prepping charge') var token = req.body.stripeToken; // Using Express var charge = stripe.charges.create({ amount: 749, currency: "usd", description: "Example charge", source: token, }, function(err, charge) { // asynchronously called console.log('charged') }); res.redirect('/jobquiz') console.log(req.body.datapoint) console.log(req.body.email) }); } }); }); 

设置忘记密码发布

 app.post('/forgot', function(req, res, next) { async.waterfall([ function(done) { crypto.randomBytes(20, function(err, buf) { var token = buf.toString('hex'); done(err, token); }); }, function(token, done) { User.findOne({ email: req.body.email }, function(err, user) { if (!user) { // console.log('error', 'No account with that email address exists.'); req.flash('error', 'No account with that email address exists.'); return res.redirect('/forgot'); } console.log('step 1') user.resetPasswordToken = token; user.resetPasswordExpires = Date.now() + 3600000; // 1 hour user.save(function(err) { done(err, token, user); }); }); }, function(token, user, done) { console.log('step 2') var smtpTrans = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'myemail', pass: 'mypassword' } }); var mailOptions = { to: user.email, from: 'myemail', subject: 'Node.js Password Reset', text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' }; console.log('step 3') smtpTrans.sendMail(mailOptions, function(err) { req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); console.log('sent') res.redirect('/forgot'); }); } ], function(err) { console.log('this err' + ' ' + err) res.redirect('/'); }); }); app.get('/forgot', function(req, res) { res.render('forgot', { User: req.user }); }); 

设置更改密码后

 app.get('/reset/:token', function(req, res) { User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) { console.log(user); if (!user) { req.flash('error', 'Password reset token is invalid or has expired.'); return res.redirect('/forgot'); } res.render('reset', { User: req.user }); }); }); app.post('/reset/:token', function(req, res) { async.waterfall([ function(done) { User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user, next) { if (!user) { req.flash('error', 'Password reset token is invalid or has expired.'); return res.redirect('back'); } user.password = req.body.password; user.resetPasswordToken = undefined; user.resetPasswordExpires = undefined; console.log('password' + user.password + 'and the user is' + user) user.save(function(err) { if (err) { console.log('here') return res.redirect('back'); } else { console.log('here2') req.logIn(user, function(err) { done(err, user); }); } }); }); }, function(user, done) { // console.log('got this far 4') var smtpTrans = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'myemail', pass: 'mypass' } }); var mailOptions = { to: user.email, from: 'myemail', subject: 'Your password has been changed', text: 'Hello,\n\n' + ' - This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' }; smtpTrans.sendMail(mailOptions, function(err) { // req.flash('success', 'Success! Your password has been changed.'); done(err); }); } ], function(err) { res.redirect('/'); }); }); 

我没有(或没有)发现你的代码有任何问题,但我有一个build议追踪错误。

这块代码是有风险的。 您可能会意外更新密码字段并触发重新密码处理。

 UserSchema.pre('save', function(next) { var user = this; var SALT_FACTOR = 5; if (!user.isModified('password')) return next(); console.log(user.password) // Check accident password update bcrypt.genSalt(SALT_FACTOR, function(err, salt) { if (err) return next(err); bcrypt.hash(user.password, salt, null, function(err, hash) { if (err) return next(err); user.password = hash; next(); }); }); }); 

把一个console.log放在if (!user.isModified('password'))检查意外的密码更新。 现在重试忘记密码,看看有没有错误。

*解决scheme:将更新密码分成新的方法,而不是将其放入预保存中,因为您可能会意外更新新密码以及其他字段

我认为这个问题可能在散列函数中。 尝试复制你的代码到我的电脑上更简单但类似的实验。

正如bcrypt文档在这里所述https://www.npmjs.com/package/bcrypt#to-hash-a-password

散列函数只需要3个参数,你在4中发送。而你的情况下的第三个参数是空的

下面是一些代码来说明这个问题,并希望解决scheme

在腌制callback里面

 bcrypt.hash(user.password, salt, null, function(err, hash) { if (err) return next(err); user.password = hash; next(); }); 

但改为将第三个参数改为callback函数。

 bcrypt.hash(user.password, salt, function(err, hash) { if (err) return next(err); user.password = hash; next(); }); 

我已经在我当前的项目中使用了这个代码,它的工作正常,我在函数UserSchema.pre('save', function(next)看到了一个小错误,当你用bcrypt.hash散列密码的时候,四个参数,但在我的代码中只有三个参数

 schema.pre('save', function(next) { var user = this; var SALT_FACTOR = 5; if(!user.isModified('password')){ return next(); } bcrypt.genSalt(SALT_FACTOR, function(err, salt) { if(err){ return next(err); } bcrypt.hash(user.password, salt, function(err, hash) { if(err){ return next(err); } user.password = hash; next(); }); }); }); 

第三个参数必须是callback函数,见bcrypt文件