gpt4 book ai didi

node.js - 无论密码如何,Bcrypt-NodeJS compare() 都会返回 false

转载 作者:行者123 更新时间:2023-12-03 12:13:57 24 4
gpt4 key购买 nike

我知道这个问题已经被问过几次(比如 hereherethere ,甚至在 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 只是散列对象,就好像它是一个字符串一样.

    最佳答案

    我知道已经找到了解决方案,但以防万一你从谷歌搜索登陆这里并遇到同样的问题,特别是如果你使用的是 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));
    });
    });
    });

    正如您所看到的,对 User 有一个嵌套保存,因为我必须将 User 模型与 Person 模型(一对一)链接起来。结果,我遇到了不匹配错误,因为我使用的是预保存函数,每次触发 User.create 或 User.save 时,都会调用该函数并重新散列现有密码。 pre-save 中的控制台语句给了我以下内容,表明该密码确实被重新散列了:

    单次注册调用后的控制台调试
    { plain: 'passwd',
    hash: '$2b$10$S2g9jIcmjGxE0aT1ASd6lujHqT87kijqXTss1XtUHJCIkAlk0Vi0S' }
    { plain: '$2b$10$S2g9jIcmjGxE0aT1ASd6lujHqT87kijqXTss1XtUHJCIkAlk0Vi0S',
    hash: '$2b$10$KRkVY3M8a8KX9FcZRX.l8.oTSupI/Fg0xij9lezgOxN8Lld7RCHXm' }

    修复,解决方案

    要解决此问题,您必须修改您的预(“保存”)代码以确保密码仅在第一次保存到数据库或已被修改时才进行哈希处理。为此,请将您的预存代码括在这些块中:
    if (user.isModified("password") || user.isNew) {
    //Perform password hashing here
    } else {
    return next();
    }

    这是我的整个预保存功能的样子
    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();
    }
    });

    希望这有助于某人。

    关于node.js - 无论密码如何,Bcrypt-NodeJS compare() 都会返回 false,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46022956/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com