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?

30
demandé sur pfried 2013-01-29 20:55:21

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
    });
});
89
répondu Noah 2016-08-18 07:43:33

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

Résultat

3
répondu xincmm 2018-01-31 08:34:15

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);
    });
};
2
répondu alex94puchades 2015-06-11 16:42:59

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.

0
répondu pfried 2013-01-29 18:40:46

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){});
0
répondu pkarc 2016-02-01 22:07:52