如何让我的 User.findByIdAndUpdate 仅在密码设置为我的新密码后运行?

How can I make my User.findByIdAndUpdate runs only after the password is set to my new password?

所以这是我的代码,基本上我想做的是在用户想要更改密码时更改密码,否则,它将保持不变。虽然,当我更改它时,它不会被散列,因为它会自动接受来自前端的输入 (req.body.password)。看起来最后一个 promise 并没有等待前一个完成并获取设置为新密码的密码。

 profileRoutes.put("/profile/:userid", (req, res) => {
  const { userid } = req.params;
  const { firstName, lastName, email, imageUrl } = req.body;
  let password = req.body.password;
  let newPassword = null;

  // We need a validation here?
  User.findById(userid)
    .then((user) => {
      console.log("user", user);
      console.log(user.password === password);

      if (user.password !== password) {
        console.log("setting the new pass");
        const salt = bcrypt.genSaltSync(10);
        newPassword = bcrypt.hashSync(password, salt);
        console.log("password:", password, "newPassword:", newPassword);
        password = newPassword;
      }
    }).then(User.findByIdAndUpdate(
        userid,
        { firstName, lastName, email, imageUrl, password },
        { new: true }
      )
        .then((response) => {
          console.log("response after update", response);
          res.status(200).json({ message: `User ${userid} has been updated` });
        })
        .catch((err) => {
          console.log(err);
          res
            .status(500)
            .json({ message: "Something went wrong updating the user" });
        })
    );
});

这是我在控制台中得到的:

    user {
[0]   imageUrl: 'http://media.istockphoto.com/vectors/default-profile-picture-avatar-photo-placeholder-vector-illustration-vector-id1223671392?k=6&m=1223671392&s=612x612&w=0&h=NGxdexflb9EyQchqjQP0m6wYucJBYLfu46KCLNMHZYM=',
[0]   role: 'USER',
[0]   fileUrl: [],
[0]   _id: 60d70093e08f660bebec5589,
[0]   firstName: 'Tiago',
[0]   lastName: 'Pereira',
[0]   email: 'tiago@gmail.com',
[0]   password: 'a$yExMB9eSs1EyqSbrvE8a1udqOMo09GG.SSyr0BJmZb70mqpcJByiC',
[0]   createdAt: 2021-06-26T10:25:23.245Z,
[0]   updatedAt: 2021-06-26T10:25:23.245Z,
[0]   __v: 0
[0] }
[0] false
[0] setting the new pass
[0] password: qwertyasd newPassword: a$Xudvsq4CkkDU7bHcQIvH.OyfhlDe1/u3Q1Qv6wmv79f4B5TSFVDi.
[0] response after update {
[0]   imageUrl: 'https://res.cloudinary.com/dulzxixhi/image/upload/v1624703139/School%27s%20Cool/wnc8vjpgunrkvolnldb4.jpg',
[0]   role: 'USER',
[0]   fileUrl: [],
[0]   _id: 60d70093e08f660bebec5589,
[0]   firstName: 'Tiago',
[0]   lastName: 'Pereira',
[0]   email: 'tiago@gmail.com',
[0]   password: 'qwertyasd',
[0]   createdAt: 2021-06-26T10:25:23.245Z,
[0]   updatedAt: 2021-06-26T10:26:20.237Z,
[0]   __v: 0
[0] }

首先,您不能直接将散列密码与普通字符串进行比较。

console.log(user.password === password); //this will always prints false

你必须使用 bcrypt.compareSync。它需要两个输入(普通字符串、散列)和 return 一个布尔值(如果匹配则为真)。

并且您在 Bcrypt 中使用同步方法,因此它不会 return 一个承诺。这意味着您不能使用 .then().

对现有代码改动最少的解决方案:

只需在 if 块中使用 findByIdAndUpdate

const isMatching = bcrypt.compareSync(password, user.password);

if (isMatching) {
        console.log("setting the new pass");
        const salt = bcrypt.genSaltSync(10);
        newPassword = bcrypt.hashSync(password, salt);
        console.log("password:", password, "newPassword:", newPassword);
        password = newPassword;

   User.findByIdAndUpdate(
        userid,
        { firstName, lastName, email, imageUrl, password },
        { new: true }
      )
        .then((response) => {
          console.log("response after update", response);
          res.status(200).json({ message: `User ${userid} has been updated` });
        })
        .catch((err) => {
          console.log(err);
          res
            .status(500)
            .json({ message: "Something went wrong updating the user" });
        })
}

解决方法其实很简单。我们要return我们要通过的东西:

        User.findById(userid)
        .then((user) => {
          if (user.password !== password) {
            const salt = bcrypt.genSaltSync(10);
            newPassword = bcrypt.hashSync(password, salt);
    
            password = newPassword;
          }
          return password;
// I am returning the password to be able to pass it to the next then() and 
// use it as follows
        })
        .then((password) => {
          User.findByIdAndUpdate(
            userid,
            {
              firstName,
              lastName,
              email,
              imageUrl,
              password,
              newChannelEmailNotification,
              newEventEmailNotification,
              newPostEmailNotification,
            },
            { new: true }
          )
            .then((response) => {
              console.log("response after update", response);
              res.status(200).json({ message: `User ${userid} has been updated` });
            })
            .catch((err) => {
              console.log(err);
              res
                .status(500)
                .json({ message: "Something went wrong updating the user" });
            });
        });
    });