14

我有一个userSchema看起来像这样的:

var userSchema = new Schema({
    name: {
      type: String
    , required: true
    , validate: [validators.notEmpty, 'Name is empty']
    }
  , username: {
      type: String
    , required: true
    , validate: [validators.notEmpty, 'Username is empty']
    }
  , email: {
      type: String
    , required: true
    , validate: [
        { validator: validators.notEmpty, msg: 'Email is empty' }
      , { validator: validators.isEmail, msg: 'Invalid email' }
      ]
    }
  , salt: String
  , hash: String
});

到目前为止,我所有的验证都在模式中进行,我想知道如何通过密码验证来实现这一点。用户在两个字段中输入密码,模型应该检查它们是否相同。

这种验证是否属于模式?我是这种验证的新手。

我应该如何验证密码?

4

7 回答 7

25

我最终发现您可以使用虚拟路径invalidate函数的组合来实现这一点,如本要点所示,用于匹配密码的相同目的:https ://gist.github.com/1350041

直接引用:

CustomerSchema.virtual('password')
.get(function() {
  return this._password;
})
.set(function(value) {
  this._password = value;
  var salt = bcrypt.gen_salt_sync(12);
  this.passwordHash = bcrypt.encrypt_sync(value, salt);
});

CustomerSchema.virtual('passwordConfirmation')
.get(function() {
  return this._passwordConfirmation;
})
.set(function(value) {
  this._passwordConfirmation = value;
});

CustomerSchema.path('passwordHash').validate(function(v) {
  if (this._password || this._passwordConfirmation) {
    if (!val.check(this._password).min(6)) {
      this.invalidate('password', 'must be at least 6 characters.');
    }
    if (this._password !== this._passwordConfirmation) {
      this.invalidate('passwordConfirmation', 'must match confirmation.');
    }
  }

  if (this.isNew && !this._password) {
    this.invalidate('password', 'required');
  }
}, null);
于 2012-12-23T22:50:32.833 回答
12

我认为密码匹配属于客户端界面,不应该到达服务器(数据库层已经太多了)。对于用户体验来说,最好不要仅仅为了告诉用户 2 个字符串不同而进行服务器往返。

至于瘦控制器、胖模型……所有这些灵丹妙药都应该回击鼻祖。在任何情况下都没有好的解决方案。在他们自己的背景下思考他们每个人。

在这里引入胖模型的想法,使您可以将功能(模式验证)用于完全不同的目的(密码匹配),并使您的应用程序依赖于您现在使用的技术。有一天你会想要改变技术,你会得到一些根本没有模式验证的东西......然后你必须记住你的应用程序的那部分功能依赖于它。而且您必须将其移回客户端或控制器。

于 2012-12-21T15:19:36.033 回答
3

我知道线程很旧,但如果它可以节省某人的时间......我的方法使用预验证钩子并且非常适合我

schema.virtual('passwordConfirmation')
    .get(function() {
      return this._passwordConfirmation;
    })
    .set(function(value) {
        this._passwordConfirmation = value;
    });

schema.pre('validate', function(next) {
    if (this.password !== this.passwordConfirmation) {
        this.invalidate('passwordConfirmation', 'enter the same password');
    }
    next();
});
于 2018-01-27T18:30:47.403 回答
2

我在 express-validator 降到 ./routes/signup.js 中的模式级别之前使用它:

exports.post = function(req, res){
  req.assert('email', 'Enter email').notEmpty().isEmail();
  req.assert('username', 'Enter username').notEmpty().isAlphanumeric().len(3,20);
  req.assert('password', 'Enter password').notEmpty().notContains(' ').len(5,20);

  res.locals.err = req.validationErrors(true);

  if ( res.locals.err ) {
    res.render('signup', { message: { error: 'Woops, looks like we need more info...'} });
    return;
  }

  ...//save
};
于 2012-12-21T00:00:28.537 回答
2

您可以通过向模型实例添加新的函数属性来将自定义方法附加到模型实例Schema.methods(您也可以使用创建模式函数Schema.statics。)这是一个验证用户密码的示例:

userSchema.methods.checkPassword = function(password) {
    return (hash(password) === this.password);
};

// You could then check if a user's password is valid like so:
UserModel.findOne({ email: 'email@gmail.com' }, function(err, user) {
    if (user.checkPassword('secretPassword')) {
        // ... user is legit
    }
});
于 2012-12-21T01:25:58.360 回答
1

注册时无需提交二次验证密码。您可能会在客户端验证这两个字段是否相等而侥幸逃脱。

于 2012-12-21T07:08:49.187 回答
0

这有点晚了,但为了人们有类似的问题。我最近遇到了类似的问题,这就是我的解决方法;我使用了一个名为 joi 的库

const joi = require('joi');
     ...
function validateUser(user){
  const schema = joi.object({
    username: joi.string().min(3).max(50).required(),
    email: joi.string().min(10).max(255).required().email(),
    password: joi.string().min(5).max(255).required(),
    password2: joi.string().valid(joi.ref('password')).required(),
  });

  return schema.validate(user);
}

exports.validate = validateUser;
于 2020-09-03T23:49:11.837 回答