2012-11-05 95 views
1

我想重構我的用戶架構。這個決定的主要原因是我不想擔心密碼和鹽的產生。所以我想將編碼邏輯從pre save處理程序移到setter。不幸的是,我不能從setter訪問對象的其他屬性(如鹽)。貓鼬如何處理密碼很好?

因此,默認的鹽不起作用,用鹽編碼密碼也不行。

我目前的實現是:

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

已有人設法移動加密,貓鼬制定者?

問候,博多

回答

1

你必須從與使用this關鍵字的二傳手內訪問其他屬性。例如:

userSchema.path('pass').set(function(v) { 

    console.log(this); // Returns model instance 

    return v; 

}); 

但是,setter不適合您的用例。正如你可能知道的那樣,HMAC-SHA1是非常昂貴的,因此將被阻塞,除非異步執行。 Mongoose setter需要該函數返回一個值,並且沒有辦法將crypto.pbkdf2()的回調結果路由到setter函數的返回值。這是異步JavaScript的一個限制,而不是Mongoose本身:你不能在異步函數中包裝一個異步調用,因爲這會破壞異步鏈的本質。

安裝程序被廣泛用於簡單的字符串操作和數據清理。

這裏只用實例的方法進行加密演示:

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

所以,唯一的辦法就是節省事件處理程序的用戶或者是有別的可能嗎? – bodokaiser

+1

我不用中間件處理它,我只是使用實例方法。看到我的第二個答案的演示。 – srquinn