【问题标题】:mongoose how to handle password encoding nicely?猫鼬如何很好地处理密码编码?
【发布时间】:2023-03-12 01:47:02
【问题描述】:

我想重构我的用户架构。这个决定的主要原因是我不想担心密码和盐的生成。所以我想将编码逻辑从预保存处理程序移动到设置器。不幸的是,我无法从 setter 访问对象的其他属性(例如 salt)。

因此,默认使用 salt 不起作用,并且使用 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 中吗?

问候,博多

【问题讨论】:

    标签: javascript node.js encryption mongoose


    【解决方案1】:

    您可以使用this 关键字从setter 中访问其他属性。例如:

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

    【讨论】:

    • 所以唯一的方法是保存事件处理程序的用户还是有其他可能的方法?
    • 我不使用中间件处理,我只是使用实例方法。请参阅我的第二个答案以获取演示。
    猜你喜欢
    • 2013-01-13
    • 1970-01-01
    • 2021-03-25
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 2015-08-10
    • 2021-08-08
    • 1970-01-01
    相关资源
    最近更新 更多