我想重构我的用户架构。这个决定的主要原因是我不想担心密码和盐的生成。所以我想将编码逻辑从预存储处理程序移动到setter。不幸的是,我无法从setter访问该对象的其他属性(如salt)。
因此默认盐不起作用并且用盐编码密码也不行。
我目前的实施是:
var userSchema = new mongoose.Schema({
username: {
type: String,
index: { unique: true, sparse: true },
required: true, lowercase: true, trim: true
},
email: {
type: String,
index: { unique: true, sparse: true },
required: true, lowercase: true, trim: true
},
salt: {
type: String,
select: false
},
password: {
type: String,
select: false
},
plainPassword: {
type: String,
select: false
}
});
// FIXME: password encoding only on change, not always
userSchema.pre('save', function(next) {
// check if a plainPassword was set
if (this.plainPassword !== '') {
// generate salt
crypto.randomBytes(64, function(err, buf) {
if (err) return next(err);
this.salt = buf.toString('base64');
// encode password
crypto.pbkdf2(this.plainPassword, this.salt, 25000, 512, function(err, encodedPassword) {
if (err) return next(err);
this.password = new Buffer(encodedPassword, 'binary').toString('base64');
this.plainPassword = '';
}.bind(this));
}.bind(this));
}
next();
});
// statics
userSchema.methods.hasEqualPassword = function(plainPassword, cb) {
crypto.pbkdf2(plainPassword, this.salt, 25000, 512, function(err, encodedPassword) {
if (err) return next(err);
encodedPassword = new Buffer(encodedPassword, 'binary').toString('base64');
cb((this.password === encodedPassword));
}.bind(this));
}
module.exports = mongoose.model('User', userSchema, 'Users');
有人设法将加密移动到mongoose setter吗?
问候,bodo
答案 0 :(得分:1)
您可以使用this
关键字访问设置器中的其他属性。例如:
userSchema.path('pass').set(function(v) {
console.log(this); // Returns model instance
return v;
});
但是,setter不适合您的用例。您可能知道,HMAC-SHA1非常昂贵,因此除非异步执行,否则将阻止。 Mongoose setter要求函数返回一个值,并且无法将crypto.pbkdf2()的回调结果路由到setter函数的返回值。这是异步javascript的限制,而不是Mongoose本身:你不能在同步函数中包装异步调用,因为这会破坏异步链的本质。
Setter最常用于简单的字符串操作和数据清理。
以下是仅使用实例方法进行加密的演示:
// Model method
userSchema.methods.hashPassword = function(pass, callback) {
// Generate salt (this should probably be async too)
var salt = this.salt = crypto.createHash('md5').update(Math.random().toString()).digest('hex');
// Salt and Hash password
crypto.pbkdf2(pass, salt, 25000, 512, callback);
});
// Implementation
var user = new User({
email: req.body.email
});
user.hashPassword(req.body.pass, function(err, hash){
user.pass = hash;
user.save();
});