我知道这个问题已经被问过几次了(比如here,here或there,甚至是Github,但没有一个答案对我有用。
我正在尝试使用Mongoose和Passport为NodeJS应用程序开发身份验证,并使用Bcrypt-NodeJS来散列用户的密码。
在我决定重构User schema并使用bcrypt的hash方法之前,一切都没有任何问题。在创建新用户时,哈希仍然有效,但我现在无法根据存储在MongoDB中的哈希值验证密码。
我知道什么?
bcrypt.compare()
总是返回false
,无论密码是否正确,无论密码是什么(我尝试了几个字符串)。
1.密码在用户创建时只散列一次(因此不会重新散列)。
1.提供给compare方法的密码和散列是正确的,顺序也是正确的。
1.密码和哈希值的类型为“String”。
1.当存储在数据库中时,哈希不会被截断(60个字符长的字符串)。
1.在数据库中获取的哈希值与用户创建时存储的哈希值相同。
代码
用户模式
为了保持清晰,有些字段被删除了,但我保留了相关部分。
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只是将对象散列为字符串。
7条答案
按热度按时间relj7zay1#
我知道解决方案已经找到了,但以防万一你在谷歌搜索中登陆这里,遇到同样的问题,特别是如果你使用的是schema.pre(“保存”)函数,有时会有多次保存同一模型的趋势,因此,重新哈希如果你在mongoDB中使用引用来创建模式关系,这一点尤其正确。下面是我的注册函数看起来像:
注册码
字符串
正如你所看到的,User上有一个嵌套的保存,因为我必须将User模型与Person模型(一对一)链接起来。结果,我遇到了不匹配错误,因为我使用了一个pre-保存函数,每次我触发User.create或User.save时,该函数都会被调用,它会重新散列现有的密码。pre-保存中的一个控制台语句给了我以下信息,这表明密码确实被重新散列了:
单次注册调用后控制台调试
型
解决办法
要解决这个问题,你必须修改你的pre(“保存”)代码,以确保密码只在第一次保存到数据库或被修改时才被哈希。要做到这一点,请将你的pre-保存代码放在以下代码块中:
型
这里是我的整个预保存功能的样子
型
希望这对某人有帮助。
0kjbasz62#
我把这个放在这里是因为它可能有一天会帮助到别人。
在我自己的例子中,即使我提供了正确的身份验证细节,我仍然使用
bcrypt.compare as false
的原因是因为模型中对数据类型的约束。因此,每次将哈希保存在DB中时,它都会被截断,以适应50
字符的约束。我有
字符串
字符串只能包含
50 characters
,但bcrypt.hash
的结果不止于此。修复
我修改了模型,因此
DataTypes.STRING(255)
vulvrdjw3#
bcrypt.hash()有3个参数.你有4个参数。
而不是
字符串
应当
型
由于您仅在创建用户时进行了哈希运算,因此可能没有正确进行哈希运算。您可能需要重新创建用户。
q0qdq0h24#
上面的答案都没有解决我的问题。
bycrpt.compare()
也总是为我返回false。我终于找到了解决方案。我在user
模式的password
字段中有一个值lowercase: true,1
。我删除了这个值,问题解决了!m4pnthwp5#
**提示:**如果您正在切换
第一个月
块总是检查返回值。
envsm3lx6#
你可以随时检查数据库中密码字段的最大长度。确保它很大。在我的例子中,我已经将其设置为500。然后代码就可以正常工作了!
ruarlubt7#
TS版本
字符串
JS版本
型