Как выполнить bcrypt.compare внутри Sequelize .then?

Я пытаюсь создать страницу входа в систему, на которой я получаю хешированный пароль из mysql db с помощью Sequelize, а затем вызываю bcrypt compare, чтобы расшифровать пароль и сравнить его с вводом входа пользователя для аутентификации.

Однако сравнение bcrypt всегда выполняется медленнее, чем результат возврата, поэтому значение всегда будет "". Я знаю, что это связано с асинхронным поведением, но я не знаю, как правильно написать этот код, чтобы он работал.

     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.info('there was an error: ', error);
    });
  }
}

const correctPassword = (enteredPassword, originalPassword) => {
  return bcrypt.compare(enteredPassword, originalPassword, (err, res) =>{
    return res;
  });
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
837
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ты почти там. Вы правильно поняли, что correctPassword выполняется асинхронно, хотя написано так, как будто это синхронно.

Во-первых, давайте сделаем correctPassword обещанием, чтобы мы могли использовать 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. Не могли бы вы вкратце объяснить мне, почему вы рекомендуете этот метод для продолжения использования обещаний?

aclspy 28.11.2018 03:14

Он более лаконичен и понятен и позволяет избежать «ада обратных вызовов» с обещаниями. В примере с "промисами" мы уже вложили одно обещание. Представим, что нам пришлось вызвать внутри этого обещания другое обещание; код станет гораздо менее читабельным. async/await позволяет нам писать код, который синхронно выглядит

mcranston18 28.11.2018 15:05

Последний пример мне кажется неуместным. Он не устанавливает переменную user. Даже когда он помещен в (then((user)), он все равно будет выдавать Unhandled rejection TypeError: Cannot read property 'password' of null, если username не найден в базе данных.

Btuman 08.08.2019 19:22

Вы не можете назначить асинхронную функцию переменной, которая позже будет использоваться кодом синхронизации. Если вы хотите выполнить функцию синхронизации, вы можете использовать await/aync. Но здесь я рекомендую вам также использовать обещание для функции сравнения.

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

Bcrypt также поддерживает обещание.

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

Другие вопросы по теме