从嵌套模式虚拟猫鼬中验证无效

时间:2016-02-29 10:35:04

标签: javascript node.js mongodb express mongoose

我的父模式定义如下:

User.js:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var PasswordSchema = require('./Password');

var UserSchema = new Schema({
    name: { type: String, required: true },
    password: PasswordSchema
});
mongoose.model('User', UserSchema);

我的孩子架构定义如下:

Password.js:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var crypto = require('crypto');

var PasswordSchema = new Schema ({
    _id: false,
    hashedPassword: { type: String, required: true },
    salt: { type: String, default: '' }
});

var passwordRegex = /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]).{8,24}$/;

PasswordSchema.virtual('password')
    .set(function (password) {
        if (passwordRegex.test(password))
        {
             this.invalidate('password', 'Invalid password format');
        }
     });

mongoose.model('Password', PasswordSchema);
module.exports = PasswordSchema;

现在我在控制器中使用了这些模型架构,如下所示:

user.js的:

require('../models/User');

var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Password = mongoose.model('Password');

router.post('/register', function (req, res, next) {
    var user = new User(req.body);
    var password = new Password({ password: 'abcd1234' });
    console.log(password.$__.validationError.errors['hashedPassword']); // Here it works I got the validation error
    user.password = password;
    user.password.$__.validationError = password.$__.validationError; // WORKAROUND
    console.log(user.password.$__.validationError.errors['hashedPassword']); // Here it doesn't work no validation error anymore ... 
    user.save(function (err) {
        if (err)
            console.log(":(");
        else
            console.log(":)");
    });
});

module.exports = router;

问题:
所以我现在的问题是,无论我发送给我的孩子的密码是什么,它都不会使该过程无效。我如何使虚拟儿童的猫鼬保存动作无效?还有其他更好的选择吗?

问题已更新:
在user.js中,为什么变量密码有验证错误,当我将其分配给user.password时,我不再有验证错误了?我该如何纠正?

**更新2:**
我找到了一个解决方法,参见user.js:我只是分配了必需的属性来生成验证错误。但看起来真的不干净还有另一种方式吗?

1 个答案:

答案 0 :(得分:1)

这是一个很好的例子https://gist.github.com/swaj/1350041,重构如下

PasswordSchema.virtual('password')
    .get(function(){
        return this._password;
    })
    .set(function (password) {
        this._password = password;
        // invoke crypto to hash and encrypt password, then assign it to hashedPassword
        this.hashedPassword = password; // this is just for test
     });

PasswordSchema.path('hashedPassword').validate(function(v) {
    if (v) {
        if (passwordRegex.test(v)) {
            this.invalidate('password', 'Invalid password format');
        }
    }
    if (!v) {
        this.validate('password', 'password required');
    }
}, null);

测试代码

var user = new User({name: 'dd'});
user.password = new Password({password: 'asdfASF123444'});
user.save(function (err) {
    if (err)
        console.log(err);
    else
        console.log("save user successfully");
});

验证错误

{ [ValidationError: User validation failed]
  message: 'User validation failed',
  name: 'ValidationError',
  errors:
   { password:
      { [ValidatorError: Invalid password format]
        properties: [Object],
        message: 'Invalid password format',
        name: 'ValidatorError',
        kind: 'user defined',
        path: 'password',
        value: undefined } } }

invalidate source code

Document.prototype.invalidate = function (path, err, val) {
  if (!this.$__.validationError) {
    this.$__.validationError = new ValidationError(this);
  }
  // ...

我们知道invalidate函数属于Document

 password.$__.validationError.errors['hashedPassword']

您为validation定义PasswordSchema,而不是UserSchema。所以user.password.$__.validationError.errors['hashedPassword']无效。

使用

测试代码
var user = new User({name: 'dd'});
user.password = new Password({password: 'asdfwe32113'});
user.save(function (err) {
    if (err)
        console.log(err);
    else
        console.log("save user successfully");
});

但是,使用此代码

将触发验证
`user.password = new Password({hashedPassword: 'asdfwe32113'});`

不会触发此验证。

因为对于virtual field,只更新了正确的虚拟名称字段,因此可以调用.set函数。

另请将这些代码添加到virtual('password'),以确保hashedPassword可以正确设置。

    if (passwordRegex.test(password)) {
         this.invalidate('password', 'Invalid password format');
    }else {
        this.hashedPassword = password;
    }   

对于第二个问题,必须在require('../models/User');之前调用mongoose.model(),以确保首先解析User.js,并将User添加到mongoose.model中在User.js中。因此user.js可以从mongoose中找到这个User模型。 JavaScript是一种解释的编程语言,因此我们应该以这种方式告诉JS引擎文件解析顺序。