Mangouste hachage de mot de passe
je cherche un bon moyen de sauvegarder un compte à MongoDB en utilisant mongoose.
mon problème est que le mot de passe est hashé de manière asynchrone. Un setter ne fonctionnera pas ici parce qu'il ne fonctionne que synchrone.
j'ai pensé à 2 manières:
créer une instance du model et la sauvegarder dans le callback du fonction de hachage.
Création d'un pré crochet sur 'enregistrer'
Est-il une bonne solution ce problème?
5 réponses
http://blog.mongodb.org/post/32866457221/password-authentication-with-mongoose-part-1
La suite est copié directement à partir du lien ci-dessus:
Utilisateur
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);
Utilisation
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 une bonne façon par l'utilisateur Mongoose et bcrypt փ
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: String,
unique: true,
index: {
unique: true
}
},
hashed_password: {
type: String,
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);
Utilisation
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
la solution officielle Mongoose exige que le modèle soit sauvegardé avant d'utiliser la méthode verifyPass, ce qui peut causer de la confusion. L'exemple suivant 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 que ce serait mieux d'utiliser le crochet, après quelques recherches, j'ai trouvé
http://mongoosejs.com/docs/middleware.html
où il est dit:
De Cas D'Utilisation:
par défaut asynchrone
je préfère cette solution parce que je peux encapsuler ceci et m'assurer qu'un compte ne peut être sauvegardé qu'avec un mot de passe.
une autre façon de le faire en utilisant les méthodes virtuals et instance:
/**
* 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);
}
};
il suffit de sauvegarder votre modèle comme, le virtuel fera son travail.
var user = {
username: "admin",
clean_password: "qwerty"
}
User.create(user, function(err,doc){});