Express-validator不会在异步验证中返回对象

时间:2016-05-24 17:51:45

标签: javascript node.js validation

我正在使用本地策略验证带有express-validator和passport.js的登录表单:

login: function() {
  passport.use('local-login', new LocalStrategy({
    passReqToCallback: true
  },
    function(req, username, password, done) {
      req.check('username', 'Incorrect user and/or password.').doesUserExists(password);
      req.check('password', 'Password cannot be empty.').notEmpty();

      req.asyncValidationErrors(true)
      .then(function(user) {
        return done(null, user);
      })
      .catch(function(errors) {
        if (errors) return done(null, false, req.flash('error', errors));
      });
    }
  ));
}

函数doesUserExists()是一个自定义异步验证,它为用户查询,比较数据库中散列密码提供的密码,并解析它:

doesUserExists: function(username, password) {
  return new Promise(function(resolve, reject) {
    User.findOne({ username: username })
    .then(function(user) {
      if (user) return user;
      if (!user) reject(user);
    })
    .then(function(user) {
      user.comparePassword(password, function(error, isMatch) {
        if (isMatch) return user;
        else reject(user);
      });
      resolve(user);
    })
    .catch(function(error) {
      if (error) reject(error);
    });
  });
}

到目前为止它工作正常,除非用户和密码匹配,并且解析了promise,没有对象(用户)返回req.asyncValidationErrors()函数,阻止其.then()阻止重定向到用户个人资料。

我必须补充一点,我对承诺很新,不确定我期待的是否应该发生。也许对它如何运作的一些误解导致我认为是错误的。

更新

目前,我决定对经过验证的用户/密码进行另一次数据库查询:

req.asyncValidationErrors(true)
  .then(function() {
    User.findOne({ username: username })
    .then(function(user) {
      return done(null, user);
    });
  })
  .catch(function(errors) {
    if (errors) {
      return done(null, false, req.flash('error', errors));
    }
  });

额外的数据库查询并不优雅,但是......

1 个答案:

答案 0 :(得分:1)

如果您只能返回User.find返回的Promise,则不需要创建新的Promise:

doesUserExists: function(username, password) {
    return User.findOne({ username: username })
    .then(function(user) {
      if (user) {
        // Also here is a mistake because we can't return inside 
        // the comparePassword callback, and that's why user is not get back
        user.comparePassword(password, function(error, isMatch) {
          if (isMatch) return user;
          else throw new Error('my error');
        });
      }
      else throw new Error('my error');
    });
}
// Now use it as follows
req
.check('username', 'Incorrect user and/or password.')
.doesUserExists(username, password)
.then(function(user){/* user authenticated */})
.catch(function(error){/* user not atuhenticated */});

所以我猜你以后可以比较密码并解决问题:

doesUserExists: function(username, password) {
    return User.findOne({ username: username })
    .then(function(user) {
      if (user) return user;
      else throw new Error('my error');
    });
}
// Now use it as follows
req
.check('username', 'Incorrect user and/or password.')
.doesUserExists(username, password)
.then(function(user){
  /* From here, user was found */
  user.comparePassword(password, function(error, isMatch) {
    if (isMatch){ /* Do whatever with the user authenticated */ }
    else { /* Do whatever you want when password don't match */ }
  });
})
.catch(function(error){/* user not found */});

如果你正在做多个异步验证,我建议你使用Promise.all()来执行并行异步函数。