Ava*_*erv 7 bcrypt mongoose node.js
我知道这个问题已经被问过几次了(比如这里,这里或那里,甚至在Github上,但没有一个答案真正对我有用......
我正在尝试使用 Mongoose 和 Passport 为 NodeJS 应用程序开发身份验证,并使用 Bcrypt-NodeJS 来哈希用户的密码。
在我决定重构用户架构并使用 bcrypt 的异步方法之前,一切都正常运行。创建新用户时哈希仍然有效,但我现在无法根据存储在 MongoDB 中的哈希来验证密码。
bcrypt.compare()
总是返回false
无论密码正确与否,无论密码是什么(我尝试了几个字符串)。为了保持清晰,一些字段已被删除,但我保留了相关部分。
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
}
});
Run Code Online (Sandbox Code Playgroud)
userSchema.statics.hashPassword = function(password, callback) {
bcrypt.hash(password, bcrypt.genSaltSync(12), null, function(err, hash) {
if (err) return callback(err);
callback(null, hash);
});
}
Run Code Online (Sandbox Code Playgroud)
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);
});
}
Run Code Online (Sandbox Code Playgroud)
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);
});
});
});
}
Run Code Online (Sandbox Code Playgroud)
这可能是我犯的一个“简单”错误,但我在几个小时内找不到任何错误......也许你有任何想法让这个方法发挥作用,我很高兴阅读它。
感谢你们。
当运行这段代码时, 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);
});
});
Run Code Online (Sandbox Code Playgroud)
我把它放在那里,以防有一天它对某人有帮助......
我在我的代码中发现了错误,该错误是在用户注册期间发生的(实际上是我没有在此处发布的唯一一段代码)。我正在散列user.password
对象而不是user.password.plaintext
......
只有通过将我的依赖项从“brcypt-nodejs”更改为“bcryptjs”,我才能找到错误,因为当要求对对象进行哈希处理时,bcryptjs 会抛出错误,而 brcypt-nodejs 只是对对象进行哈希处理,就好像它是字符串一样。
我知道解决方案已经找到,但以防万一您从谷歌搜索登陆这里并遇到相同的问题,特别是如果您使用 schema.pre("save") 函数,有时会倾向于保存相同的内容模型多次,因此每次都重新散列密码。如果您使用 mongoDB 中的引用来创建架构关系,则尤其如此。这是我的注册功能的样子:
注册码
User.create(newUser, (err, user) => {
if (err || !user) {
console.warn("Error at stage 1");
return res.json(transformedApiRes(err, "Signup error", false)).status(400);
}
let personData: PersonInterface = <PersonInterface>{};
personData.firstName = req.body.first_name;
personData.lastName = req.body.last_name;
personData.user = user._id;
Person.create(personData, function (err1: Error, person: any): any {
if (err1 || !person) {
return res.json(transformedApiRes(err1, "Error while saving to Persons", false));
}
/* One-to-One relationship */
user.person = person;
user.save(function (err, user) {
if (err || !user) {
return res.json({error: err}, "Error while linking user and person models", false);
}
emitter.emit("userRegistered", user);
return res.json(transformedApiRes(user, `Signup Successful`, true));
});
});
});
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,用户上有一个嵌套保存,因为我必须将用户模型与人员模型链接起来(一对一)。结果,我遇到了不匹配错误,因为我使用了预保存函数,每次触发 User.create 或 User.save 时,都会调用该函数并重新哈希现有密码。预保存中的控制台语句给了我以下内容,表明密码确实被重新散列:
单次注册调用后控制台调试
{ plain: 'passwd',
hash: '$2b$10$S2g9jIcmjGxE0aT1ASd6lujHqT87kijqXTss1XtUHJCIkAlk0Vi0S' }
{ plain: '$2b$10$S2g9jIcmjGxE0aT1ASd6lujHqT87kijqXTss1XtUHJCIkAlk0Vi0S',
hash: '$2b$10$KRkVY3M8a8KX9FcZRX.l8.oTSupI/Fg0xij9lezgOxN8Lld7RCHXm' }
Run Code Online (Sandbox Code Playgroud)
修复、解决方案
要解决此问题,您必须修改您的预(“保存”)代码,以确保仅在第一次将密码保存到数据库或已修改密码时才对密码进行哈希处理。为此,请将预保存代码包含在这些块中:
if (user.isModified("password") || user.isNew) {
//Perform password hashing here
} else {
return next();
}
Run Code Online (Sandbox Code Playgroud)
这是我的整个预保存功能的样子
UsersSchema.pre("save", function (next: NextFunction): any {
let user: any = this;
if (user.isModified("password") || user.isNew) {
bcrypt.genSalt(10, function (err: Error, salt: string): any {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, function (err: Error, hash: string) {
if (err) {
console.log(err);
return next(err);
}
console.warn({plain: user.password, hash: hash});
user.password = hash;
next();
});
});
} else {
return next();
}
});
Run Code Online (Sandbox Code Playgroud)
希望这对某人有帮助。
bcrypt.hash()有 3 个参数...由于某种原因你有 4 个参数。
代替
bcrypt.hash(password, bcrypt.genSaltSync(12), null, function(err, hash) {
Run Code Online (Sandbox Code Playgroud)
它应该是
bcrypt.hash(password, bcrypt.genSaltSync(12), function(err, hash) {
Run Code Online (Sandbox Code Playgroud)
由于您仅在用户创建期间进行散列,因此您可能没有正确进行散列。您可能需要重新创建用户。
归档时间: |
|
查看次数: |
12521 次 |
最近记录: |