【问题标题】:How to execute bcrypt.compare inside Sequelize .then?如何在 Sequelize .then 中执行 bcrypt.compare?
【发布时间】:2018-11-28 23:43:14
【问题描述】:

我正在尝试构建一个登录页面,在该页面中我使用 Sequelize 从 mysql db 获取哈希密码,然后调用 bcrypt compare 对密码进行去哈希并将其与用户的登录输入进行比较以进行身份​​验证。

但是,bcrypt compare 的执行速度总是比返回值慢,导致值始终为“”。我知道这与异步行为有关,但我不知道如何正确编写此代码以使其工作。

     authenticate: (req, res) => {

    let userDetails = req.query;

    User.findOne({
      where: {
        username: userDetails.username
      }
    })
    .then((user) => {
      // How can I make this so, correctPassword() finishes
      // and then the authenticated variable will be either false or true?

      let authenticated = correctPassword(userDetails.password, user.password);
      return authenticated;
    })
    .then((authenticated) => {
      // right now authenticated is "" in client side console.

      res.send(authenticated);
    })
    .catch((error) => {
      console.log('there was an error: ', error);
    });
  }
}

const correctPassword = (enteredPassword, originalPassword) => {
  return bcrypt.compare(enteredPassword, originalPassword, (err, res) =>{
    return res;
  });
}

【问题讨论】:

    标签: javascript node.js asynchronous sequelize.js bcrypt


    【解决方案1】:

    你快到了。你的直觉是正确的 correctPassword 异步执行,虽然它被写成好像它是同步的。

    首先,让我们将correctPassword 设为一个promise,这样我们就可以使用async/await 或调用.then

    const correctPassword = (enteredPassword, originalPassword) => {
      return new Promise(resolve => {
        bcrypt.compare(enteredPassword, originalPassword, (err, res) =>{
          resolve(res)
        });  
      })
    }
    

    接下来,您有两种方法可以确保代码中的操作顺序正确执行:

    (推荐)使用async/await 语法允许我们编写看起来同步的代码:

    authenticate: async (req, res) => {
      let userDetails = req.query;
      try {
        const user = await User.findOne({
          where: {
            username: userDetails.username
          }
        });
    
        const authenticated = await correctPassword(userDetails.password, user.password);
    
        res.send(authenticated);        
      } catch(e) {
        res.status(400).send(e)
      }
    }
    

    继续使用承诺:

    authenticate: (req, res) => {
      let userDetails = req.query;
      User.findOne({
        where: {
          username: userDetails.username
        }
      }).then(() => {
        correctPassword(userDetails.password, user.password)
          .then(authenticated => {
            res.send(authenticated)
          })
          .catch(e => {
            res.send(e)
          })
      })
    }
    

    【讨论】:

    • 谢谢。这很有效,我接受了你的建议,使用 async/await 语法。你能简单地向我解释一下为什么你推荐这种方法来继续使用 Promise 吗?
    • 更简洁干净,让我们可以避免使用 promises 的“回调地狱”。在“promises”示例中,我们已经必须嵌套一个 promise。假设我们必须在其中调用另一个承诺;代码的可读性会大大降低。 async/await 允许我们编写看起来同步的代码
    • 最后一个例子对我来说看起来很糟糕。它没有设置user 变量。即使将一个放在(then((user))中,当在数据库中找不到username 时,它仍然会抛出一个Unhandled rejection TypeError: Cannot read property 'password' of null
    【解决方案2】:

    您不能将异步函数分配给稍后由同步代码使用的变量。如果你想做同步功能,你可以使用await/aync。但是在这里我建议你也使用 promise 来比较函数。

    User.findOne({
      where: {
        username: userDetails.username
      }
    })
    .then((user) => {
      return correctPassword(userDetails.password, user.password);
    })
    .then((authenticated) => {
      res.send(authenticated);
    })
    

    Bcrypt 也支持 Promise。

    const correctPassword = (enteredPassword, originalPassword) => {
      return bcrypt.compare(enteredPassword, originalPassword).then((res) =>{
        return res;
      });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-08
      • 2019-08-30
      • 1970-01-01
      • 2011-08-20
      • 1970-01-01
      • 2021-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多