MEAN Stack重置密码时无法保存bcrypt加密密码求助
Hey there! Let's break down why your hashed password isn't saving correctly when users reset their passwords. I’ve spotted two key issues in your code that are causing this problem.
Key Problems Identified
1. Async Operation Race Condition
bcrypt.hash() is an asynchronous function, but you’re calling user.save() immediately after starting the hash process. This means user.save() runs before the hash is generated and assigned to user.userPassword—so you end up saving the plain-text password instead of the hashed version.
2. Incorrect findOneAndUpdate Usage
Your findOneAndUpdate implementation has a syntax error. The post-find logic you wrote (where you update the password and clear reset tokens) is misplaced—findOneAndUpdate doesn’t accept a second callback like that. This means that critical password-update code never actually runs.
Corrected Reset Password Function
Here’s the fixed version of your resetpassword function, using async/await to eliminate callback hell and properly handle asynchronous flows:
// Make sure to define saltRounds at the top of your file! const saltRounds = 10; exports.resetpassword = async function(req, res) { try { // Step 1: Locate user with valid, unexpired reset token const user = await User.findOne({ reset_password_token: req.body.token, reset_password_expire: {$gt: Date.now()} }); if (!user) { console.log('Token Expire or Invalid'); return res.json({status: false, message: 'Token Invalid or Expired'}); } // Step 2: Hash the new password (wait for async hash to finish) const hashedPassword = await bcrypt.hash(req.body.userPassword, saltRounds); user.userPassword = hashedPassword; // Step 3: Clear reset token fields user.reset_password_token = undefined; user.reset_password_expire = undefined; // Step 4: Save the updated user await user.save(); console.log('Password updated successfully'); // Step 5: Send password reset confirmation email const smtpTrans = nodemailer.createTransport({ service: 'Gmail', auth: { user: 'myemail', pass: 'mypass' } }); const data = { to: user.userEmail, from: 'myemail', subject: 'Password Reset Confirmation', text: `Hello ${user.userName},\n\n - This is a confirmation that the password for your account ${user.userEmail} has just been changed.\n` }; await smtpTrans.sendMail(data); console.log('Password change confirmation email sent'); return res.json({status: true, message: 'Password has been reset successfully'}); } catch (err) { console.error('Error during password reset:', err); return res.status(500).json({status: false, message: 'Failed to reset password', error: err.message}); } };
Additional Tips
- Async/Await Clarity: Using
async/awaitmakes your code far easier to read and debug compared toasync.waterfall—it ensures we wait for each async operation to complete before moving on. - Bcrypt Promise Support: Most recent bcrypt versions support promises natively, but if yours doesn’t, wrap
bcrypt.hashwith Node.js’s built-inutil.promisifyto use it withawait. - Schema Note: Your
userPasswordfield hasbcrypt: true—this only works if you’re using a plugin likemongoose-bcrypt. Since you’re handling hashing manually, you can keep this or remove it without affecting your code.
内容的提问来源于stack exchange,提问作者Dr Virus

