环回自定义密码验证
Loopback custom password validation
非常简单的问题:如果我尝试在用户模型中验证密码,似乎我只能验证已经加密的密码?
例如,如果我使用
Customer.validatesLengthOf('password', { min: 8, message: 'Too short' })
然后检查加密密码(总是超过 8 个字符),所以不好...如果我尝试使用自定义验证,我如何才能访问原始密码(原始 req.body.password 基本上)?
好的,没有答案,所以我正在做的是使用远程挂钩来访问原始明文密码,现在就可以了。
var plainPwd
Customer.beforeRemote( 'create', function (ctx, inst, next) {
plainPwd = ctx.req.body.password
next()
})
然后我可以在自定义验证中使用它:
Customer.validate( 'password', function (err, res) {
const pattern = new RegExp(/some-regex/)
if (plainPwd && ! pattern.test( plainPwd )) err()
}, { message: 'Invalid format' })
好吧,我想上面的答案很新颖,显然是可以接受的,但是如果你想要一个真正简单的解决方案,只需要完成一些基本的验证而不需要太多代码,那么 loopback-mixin-complexity 是适合你的解决方案。
如果您不想创建另一个依赖项,那么您可以继续自定义 mixin,您可以将其添加到您的用户模型或任何其他需要某种验证的模型中,并且它会为您做验证。
这里有一个关于如何创建这样的 mixin 的示例代码
module.exports = function(Model, options) {
'use strict';
Model.observe('before save', function event(ctx, next) { //Observe any insert/update event on Model
if (ctx.instance) {
if(!yourValidatorFn(ctx.instance.password) )
next('password not valid');
else
next();
}
else {
if(!yourValidatorFn(ctx.data.password) )
next('password not valid');
else
next();
}
});
};
编辑(2019 年 8 月 20 日):我不确定这在最新的环回版本中是否仍然是一个问题。
其实这是一个known problem in loopback. The tacitly approved solution is to override the <UserModel>.validatePassword()
method with your own。 YMMV.
akapaul commented on Jan 10, 2017 •
I've found another way to do this. In common model User there is a
method called validatePassword. If we extend our UserModel from User,
we can redefine this method in JS, like following:
var g = require('loopback/lib/globalize');
module.exports = function(UserModel) {
UserModel.validatePassword = function(plain) {
var err,
passwordProperties = UserModel.definition.properties.password;
if (plain.length > passwordProperties.max) {
err = new Error (g.f('Password too long: %s (maximum %d symbols)', plain, passwordProperties.max));
err.code = 'PASSWORD_TOO_LONG';
} else if (plain.length < passwordProperties.min) {
err = new Error(g.f('Password too short: %s (minimum %d symbols)', plain, passwordProperties.min));
err.code = 'PASSWORD_TOO_SHORT';
} else if(!(new RegExp(passwordProperties.pattern, 'g').test(plain))) {
err = new Error(g.f('Invalid password: %s (symbols and numbers are allowed)', plain));
err.code = 'INVALID_PASSWORD';
} else {
return true;
}
err.statusCode = 422;
throw err;
};
};
This works for me. I don't think that g (globalize) object is required
here, but I added this, just in case. Also, I've added my validator
options in JSON definition of UserModel, because of Loopback docs
为了使用上面的代码,可以像这样将它们的验证规则放在模型的 .json
定义中(参见 max
、min
和 pattern
properties.password
):
{
"name": "UserModel",
"base": "User",
...
"properties": {
...
"password": {
"type": "string",
"required": true,
...
"max": 50,
"min": 8,
"pattern": "(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])(?=.*[a-z])^.*$"
},
...
},
...
}
非常简单的问题:如果我尝试在用户模型中验证密码,似乎我只能验证已经加密的密码? 例如,如果我使用
Customer.validatesLengthOf('password', { min: 8, message: 'Too short' })
然后检查加密密码(总是超过 8 个字符),所以不好...如果我尝试使用自定义验证,我如何才能访问原始密码(原始 req.body.password 基本上)?
好的,没有答案,所以我正在做的是使用远程挂钩来访问原始明文密码,现在就可以了。
var plainPwd
Customer.beforeRemote( 'create', function (ctx, inst, next) {
plainPwd = ctx.req.body.password
next()
})
然后我可以在自定义验证中使用它:
Customer.validate( 'password', function (err, res) {
const pattern = new RegExp(/some-regex/)
if (plainPwd && ! pattern.test( plainPwd )) err()
}, { message: 'Invalid format' })
好吧,我想上面的答案很新颖,显然是可以接受的,但是如果你想要一个真正简单的解决方案,只需要完成一些基本的验证而不需要太多代码,那么 loopback-mixin-complexity 是适合你的解决方案。
如果您不想创建另一个依赖项,那么您可以继续自定义 mixin,您可以将其添加到您的用户模型或任何其他需要某种验证的模型中,并且它会为您做验证。
这里有一个关于如何创建这样的 mixin 的示例代码
module.exports = function(Model, options) {
'use strict';
Model.observe('before save', function event(ctx, next) { //Observe any insert/update event on Model
if (ctx.instance) {
if(!yourValidatorFn(ctx.instance.password) )
next('password not valid');
else
next();
}
else {
if(!yourValidatorFn(ctx.data.password) )
next('password not valid');
else
next();
}
});
};
编辑(2019 年 8 月 20 日):我不确定这在最新的环回版本中是否仍然是一个问题。
其实这是一个known problem in loopback. The tacitly approved solution is to override the <UserModel>.validatePassword()
method with your own。 YMMV.
akapaul commented on Jan 10, 2017 •
I've found another way to do this. In common model User there is a method called validatePassword. If we extend our UserModel from User, we can redefine this method in JS, like following:
var g = require('loopback/lib/globalize'); module.exports = function(UserModel) { UserModel.validatePassword = function(plain) { var err, passwordProperties = UserModel.definition.properties.password; if (plain.length > passwordProperties.max) { err = new Error (g.f('Password too long: %s (maximum %d symbols)', plain, passwordProperties.max)); err.code = 'PASSWORD_TOO_LONG'; } else if (plain.length < passwordProperties.min) { err = new Error(g.f('Password too short: %s (minimum %d symbols)', plain, passwordProperties.min)); err.code = 'PASSWORD_TOO_SHORT'; } else if(!(new RegExp(passwordProperties.pattern, 'g').test(plain))) { err = new Error(g.f('Invalid password: %s (symbols and numbers are allowed)', plain)); err.code = 'INVALID_PASSWORD'; } else { return true; } err.statusCode = 422; throw err; }; };
This works for me. I don't think that g (globalize) object is required here, but I added this, just in case. Also, I've added my validator options in JSON definition of UserModel, because of Loopback docs
为了使用上面的代码,可以像这样将它们的验证规则放在模型的 .json
定义中(参见 max
、min
和 pattern
properties.password
):
{
"name": "UserModel",
"base": "User",
...
"properties": {
...
"password": {
"type": "string",
"required": true,
...
"max": 50,
"min": 8,
"pattern": "(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])(?=.*[a-z])^.*$"
},
...
},
...
}