Passport, Bcryptjs, Асинхронность/Ожидание: функция проверки передает любой ввод пароля как истинный

#node.js #express #async-await #passport.js #asynchronous-javascript

Вопрос:

Все в моей стратегии passport-local, похоже, работает, за исключением обратного вызова verifycall, где оценка истинности validatesPassword функции независимо возвращает значение true. Проблема может быть связана с тем, что validatesPassword это асинхронная функция, и Promise {lt;pendinggt;} вывод, когда функция работает не по порядку, не является ложным:

из файла паролей:

 async function validatesPassword(passwordInput, dbHash) {  let comparedInput = await bcrypt.compare(passwordInput, dbHash)   //console.log("this is whats returned from compared Input "   comparedInput)  return comparedInput; }   

Консоль.вход в validatesPassword систему обычно печатается после вызова условного оператора в функции passport verifyCallback() в файле моего паспорта:

 User.findOne(email)  .then((dbResponse) =gt; {  //console.log(dbResponse[0][0]);  let user = dbResponse[0][0];  if (!user) { return done(null, false); }  //no error, but also no user    const isValid = validatesPassword(password, user.hash);  //const isValid = false;  if (isValid) {  return done(null, user);  } else {  return done(null, false);  }   })  .catch((err) =gt; {  console.log(err);  done(err);  }); }   const strategy = new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, verifyCallback); passport.use(strategy) ...   

Как видно выше, единственный способ, которым я могу вывести значение false из вышеупомянутого условия, — это явно установить isValid значение false. Каков был бы наилучший способ заставить условное условие дождаться функции сравнения паролей ( validatesPassword ) и оценить ее возвращаемую логическую функцию? Должен ли я обещать validatesPassword и добавить условное условие внутри (я пытался реализовать это самостоятельно, но безуспешно) этой функции и передать все это verifyCallback функции в файле моего паспорта?

Ответ №1:

validatesPassword() это async функция. Как таковой, он ВСЕГДА возвращает обещание.

Итак, когда вы сделаете это:

 const isValid = validatesPassword(password, user.hash);  if (isValid) {  // ...  }  

Это всегда будет правдой, потому isValid что это обещание, так if (isValid) что оно всегда пройдет. Вместо этого вы должны извлечь выгоду из обещания с .then() помощью или await , например:

 const isValid = await validatesPassword(password, user.hash);  if (isValid) {  // ...  }  

Чтобы использовать await его там, вам придется создать родительскую функцию async .


Используя .then() и комбинируя код, который вы показываете в своем вопросе, он может выглядеть следующим образом:

 User.findOne(email).then((dbResponse) =gt; {  let user = dbResponse[0][0];  if (!user) {   return done(null, false);   }  return validatesPassword(password, user.hash).then(isValid =gt; {  done(null, isValid ? user : false);  }); }).catch((err) =gt; {  console.log(err);  done(err); });  

Имейте в виду пару вещей об использовании async и await :

  1. async Функция всегда возвращает обещание.
  2. Он возвращает это обещание, когда async функция попадает в первую await очередь, и выполнение этой async функции приостанавливается в этот момент, но он немедленно возвращает обещание, и выполнение вызывающего кода, который получает это обещание, продолжается.
  3. Некоторое время спустя, когда внутреннее обещание, которое вы используете await с помощью, разрешится, функция, которая ранее была приостановлена, await возобновит выполнение.
  4. Когда вы в конечном итоге получите возвращаемое значение в этой функции , например ваше return comparedInput; , это возвращаемое значение будет разрешенным значением обещания, которое ранее было возвращено из async функции. Таким образом, хотя это выглядит как синхронное возвращаемое значение, это не так. Поскольку функция есть async , возвращаемое значение становится разрешенным значением возвращаемого обещания.
  5. Затем вызывающий абонент должен использовать либо await или .then() , чтобы получить разрешенное значение из обещания.

Комментарии:

1. Я опубликовал свое решение, был бы признателен, если бы вы взглянули и сказали мне, что вы думаете, если сможете.

2. @DeltaFlyer — Я добавил новую версию к своему ответу.

Ответ №2:

от ответа jfriend00 у меня в голове завертелись колесики, хотя сначала я не был уверен, что понял. Я просмотрел использование условных выражений в обещаниях и условных выражениях, которые полагаются на обещания, и придумал это решение, в котором я .затем()’d validatesPassword , а затем добавил условие внутри этого:

 ... User.findOne(email)  .then((dbResponse) =gt; {  //console.log(dbResponse[0][0]);  let user = dbResponse[0][0];  if (!user) { return done(null, false); }  //no error, but also no user   console.log(  `  here's the dbResponse Object:  user: ${user.username},  password: ${user.hash},   `  );   validatesPassword(password, user.hash)  .then((isValid) =gt; {  if (isValid) {  return done(null, user);  } else {  return done(null, false);  }  })  //const isValid = false;    })  .catch((err) =gt; {  console.log(err);  done(err);  }); } ...  

Я не уверен, что это то, что предлагал jfriend00, но это решение, похоже, работает.

Комментарии:

1. Посмотрите, что я добавил к своему ответу. То, что у вас здесь есть, в основном в порядке. Одной вещи вам не хватает, если validatesPassword() вы отвергаете, вы не справляетесь с этим отказом. Я вернул это обещание, так что отказ будет пойман на более высоком уровне .catch() . Разрешение отклонениям распространяться вверх может упростить обнаружение ошибок.