【发布时间】:2018-02-11 20:38:03
【问题描述】:
我知道这个问题已经被问过几次了(比如here、here 或there,甚至在Github,但没有一个答案对我真正有用...
我正在尝试使用 Mongoose 和 Passport 为 NodeJS 应用程序开发身份验证,并使用 Bcrypt-NodeJS 对用户的密码进行哈希处理。
在我决定重构用户模式并使用 bcrypt 的异步方法之前,一切都正常工作。创建新用户时哈希仍然有效,但我现在无法根据存储在 MongoDB 中的哈希验证密码。
我知道什么?
-
bcrypt.compare()总是返回false无论密码是否正确,无论密码是什么(我尝试了几个字符串)。 - 密码仅在用户创建时被散列一次(因此不会重新散列)。
- 提供给 compare 方法的密码和哈希是正确的,顺序正确。
- 密码和哈希是“字符串”类型。
- 哈希值在存储在数据库中时不会被截断(60 个字符长的字符串)。
- 在数据库中提取的哈希值与用户创建时存储的哈希值相同。
代码
用户架构
为了清楚起见,已经删除了一些字段,但我保留了相关部分。
var userSchema = mongoose.Schema({
// Local authentication
password: {
hash: {
type: String,
select: false
},
modified: {
type: Date,
default: Date.now
}
},
// User data
profile: {
email: {
type: String,
required: true,
unique: true
}
},
// Dates
lastSignedIn: {
type: Date,
default: Date.now
}
});
密码散列
userSchema.statics.hashPassword = function(password, callback) {
bcrypt.hash(password, bcrypt.genSaltSync(12), null, function(err, hash) {
if (err) return callback(err);
callback(null, hash);
});
}
密码比较
userSchema.methods.comparePassword = function(password, callback) {
// Here, `password` is the string entered in the login form
// and `this.password.hash` is the hash stored in the database
// No problem so far
bcrypt.compare(password, this.password.hash, function(err, match) {
// Here, `err == null` and `match == false` whatever the password
if (err) return callback(err);
callback(null, match);
});
}
用户认证
userSchema.statics.authenticate = function(email, password, callback) {
this.findOne({ 'profile.email': email })
.select('+password.hash')
.exec(function(err, user) {
if (err) return callback(err);
if (!user) return callback(null, false);
user.comparePassword(password, function(err, match) {
// Here, `err == null` and `match == false`
if (err) return callback(err);
if (!match) return callback(null, false);
// Update the user
user.lastSignedIn = Date.now();
user.save(function(err) {
if (err) return callback(err);
user.password.hash = undefined;
callback(null, user);
});
});
});
}
这可能是我犯的一个“简单”错误,但我在几个小时内没有发现任何问题...希望您有任何想法使该方法有效,我很乐意阅读。
谢谢你们。
编辑:
运行这段代码时,match实际上等于true。所以我知道我的方法是正确的。我怀疑这与数据库中哈希的存储有关,但我真的不知道什么会导致这个错误发生。
var pwd = 'TestingPwd01!';
mongoose.model('User').hashPassword(pwd, function(err, hash) {
console.log('Password: ' + pwd);
console.log('Hash: ' + hash);
user.password.hash = hash;
user.comparePassword(pwd, function(err, match) {
console.log('Match: ' + match);
});
});
编辑 2(和解决方案):
我把它放在那里以防有一天它对某人有帮助......
我在我的代码中发现了错误,这是在用户注册期间发生的(实际上是我没有在此处发布的唯一一段代码)。我正在散列 user.password 对象而不是 user.password.plaintext...
只有通过将我的依赖项从“brcypt-nodejs”更改为“bcryptjs”,我才能找到错误,因为当要求对对象进行哈希处理时,bcryptjs 会抛出错误,而 brcypt-nodejs 只是像处理对象一样对对象进行哈希处理是一个字符串。
【问题讨论】:
-
如果没有回答您的问题,您不应该标记最佳答案
-
@raam86 我找到了解决方案,因为该答案上有 cmets,这不是最好的答案吗?不?好的,我会记住的。