mongoose密码哈希

我正在寻找一种使用mongoose将帐户保存到MongoDB的好方法。

我的问题是:密码asynchronous散列。 制定者不会在这里工作,因为它只能同步工作。

我想了两个办法:

  • 创build模型的实例并将其保存在哈希函数的callback中。

  • 在“保存”上创build预钩

这个问题有什么好的解决方法吗?

MongoDB博客有一个很好的文章,详细介绍如何实现用户authentication。

http://blog.mongodb.org/post/32866457221/password-authentication-with-mongoose-part-1

以下是直接从上面的链接复制:

用户模型

var mongoose = require('mongoose'), Schema = mongoose.Schema, bcrypt = require('bcrypt'), SALT_WORK_FACTOR = 10; var UserSchema = new Schema({ username: { type: String, required: true, index: { unique: true } }, password: { type: String, required: true } }); UserSchema.pre('save', function(next) { var user = this; // only hash the password if it has been modified (or is new) if (!user.isModified('password')) return next(); // generate a salt bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) { if (err) return next(err); // hash the password using our new salt bcrypt.hash(user.password, salt, function(err, hash) { if (err) return next(err); // override the cleartext password with the hashed one user.password = hash; next(); }); }); }); UserSchema.methods.comparePassword = function(candidatePassword, cb) { bcrypt.compare(candidatePassword, this.password, function(err, isMatch) { if (err) return cb(err); cb(null, isMatch); }); }; module.exports = mongoose.model('User', UserSchema); 

用法

 var mongoose = require(mongoose), User = require('./user-model'); var connStr = 'mongodb://localhost:27017/mongoose-bcrypt-test'; mongoose.connect(connStr, function(err) { if (err) throw err; console.log('Successfully connected to MongoDB'); }); // create a user a new user var testUser = new User({ username: 'jmar777', password: 'Password123'; }); // save user to database testUser.save(function(err) { if (err) throw err; }); // fetch user and test password verification User.findOne({ username: 'jmar777' }, function(err, user) { if (err) throw err; // test a matching password user.comparePassword('Password123', function(err, isMatch) { if (err) throw err; console.log('Password123:', isMatch); // -> Password123: true }); // test a failing password user.comparePassword('123Password', function(err, isMatch) { if (err) throw err; console.log('123Password:', isMatch); // -> 123Password: false }); }); 

Mongoose官方解决scheme需要在使用verifyPass方法之前保存模型,这可能会导致混淆。 以下会为你工作吗? (我正在使用scrypt而不是bcrypt)。

 userSchema.virtual('pass').set(function(password) { this._password = password; }); userSchema.pre('save', function(next) { if (this._password === undefined) return next(); var pwBuf = new Buffer(this._password); var params = scrypt.params(0.1); scrypt.hash(pwBuf, params, function(err, hash) { if (err) return next(err); this.pwHash = hash; next(); }); }); userSchema.methods.verifyPass = function(password, cb) { if (this._password !== undefined) return cb(null, this._password === password); var pwBuf = new Buffer(password); scrypt.verify(this.pwHash, pwBuf, function(err, isMatch) { return cb(null, !err && isMatch); }); }; 

我想在经过一些调查后发现,使用hook会更好

http://mongoosejs.com/docs/middleware.html

它在哪里说:

用例:

asynchronous默认值

我更喜欢这个解决scheme,因为我可以封装这个,并确保一个帐户只能用密码保存。

使用虚拟和实例方法做到这一点的另一种方法是:

 /** * Virtuals */ schema.virtual('clean_password') .set(function(clean_password) { this._password = clean_password; this.password = this.encryptPassword(clean_password); }) .get(function() { return this._password; }); schema.methods = { /** * Authenticate - check if the passwords are the same * * @param {String} plainText * @return {Boolean} * @api public */ authenticate: function(plainPassword) { return bcrypt.compareSync(plainPassword, this.password); }, /** * Encrypt password * * @param {String} password * @return {String} * @api public */ encryptPassword: function(password) { if (!password) return ''; return bcrypt.hashSync(password, 10); } }; 

只要保存你的模型,虚拟就可以完成它的工作。

 var user = { username: "admin", clean_password: "qwerty" } User.create(user, function(err,doc){});