You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MEAN Stack重置密码时无法保存bcrypt加密密码求助

Fixing Bcrypt Password Save Issue in Your Password Reset Flow

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/await makes your code far easier to read and debug compared to async.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.hash with Node.js’s built-in util.promisify to use it with await.
  • Schema Note: Your userPassword field has bcrypt: true—this only works if you’re using a plugin like mongoose-bcrypt. Since you’re handling hashing manually, you can keep this or remove it without affecting your code.

内容的提问来源于stack exchange,提问作者Dr Virus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:56:09