Mot de passe Mongoose

Je cherche un bon moyen de sauvegarder un compte sur MongoDB en utilisant mongoose.

Mon problème est le suivant: le mot de passe est haché de manière asynchrone. Un poseur ne travaillera pas ici car il ne fonctionne que de manière synchrone.

J’ai pensé à 2 façons:

Existe-t-il une bonne solution à ce problème?

Le blog de mongodb contient un excellent article décrivant comment implémenter l’authentification d’utilisateur.

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

Ce qui suit est directement copié du lien ci-dessus:

Modèle d’utilisateur

var mongoose = require('mongoose'), Schema = mongoose.Schema, bcrypt = require('bcrypt'), SALT_WORK_FACTOR = 10; var UserSchema = new Schema({ username: { type: Ssortingng, required: true, index: { unique: true } }, password: { type: Ssortingng, 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); 

Usage

 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 }); }); 

Je pense que c’est un bon moyen de l’utilisateur Mongoose et bcrypt

Modèle d’utilisateur

 /** * Module dependences */ const mongoose = require('mongoose'); const Schema = mongoose.Schema; const bcrypt = require('bcrypt'); const SALT_WORK_FACTOR = 10; // define User Schema const UserSchema = new Schema({ username: { type: Ssortingng, unique: true, index: { unique: true } }, hashed_password: { type: Ssortingng, default: '' } }); // Virtuals UserSchema .virtual('password') // set methods .set(function (password) { this._password = password; }); UserSchema.pre("save", function (next) { // store reference const user = this; if (user._password === undefined) { return next(); } bcrypt.genSalt(SALT_WORK_FACTOR, function (err, salt) { if (err) console.log(err); // hash the password using our new salt bcrypt.hash(user._password, salt, function (err, hash) { if (err) console.log(err); user.hashed_password = hash; next(); }); }); }); /** * Methods */ 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); 

Usage

 signup: (req, res) => { let newUser = new User({ username: req.body.username, password: req.body.password }); // save user newUser.save((err, user) => { if (err) throw err; res.json(user); }); } 

Résultat

Résultat

La solution officielle de Mongoose nécessite que le modèle soit enregistré avant d’utiliser la méthode verifyPass, ce qui peut être source de confusion. Ce qui suit fonctionnerait-il pour vous? (J’utilise scrypt au lieu de 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); }); }; 

Je suppose qu’il serait préférable d’utiliser le crochet, après quelques recherches, j’ai trouvé

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

Où il est dit:

Cas d’utilisation:

valeurs par défaut asynchrones

Je préfère cette solution car je peux l’encapsuler et m’assurer qu’un compte ne peut être enregistré qu’avec un mot de passe.

Une autre façon de faire cela en utilisant des méthodes d’instances virtuelles et d’instances virtuelles:

 /** * 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 {Ssortingng} plainText * @return {Boolean} * @api public */ authenticate: function(plainPassword) { return bcrypt.compareSync(plainPassword, this.password); }, /** * Encrypt password * * @param {Ssortingng} password * @return {Ssortingng} * @api public */ encryptPassword: function(password) { if (!password) return ''; return bcrypt.hashSync(password, 10); } }; 

Sauvegardez simplement votre modèle, le virtuel fera son travail.

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