首页 > 解决方案 > 为什么更改 MongoDB versionKey "_v" 时 bcrypt 会失败?

问题描述

我正在尝试在 Nodejs 中实现身份验证流程。我使用 MongoDB 作为数据库,“bcrypt 密码哈希”和“mongoose 文档版本控制”存在问题。

当我创建一个新帐户并使用此帐户登录时,没有问题,一切正常。但是当我对子文档进行更改时,versionKey "_v" 正在更改,我无法再访问该帐户。它向我抛出了来自护照中间件的“无效密码”错误。我不明白为什么会这样。

这是结构:

猫鼬用户模型

const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
    {
        name: { type: String, required: true },
        surname: { type: String, required: true },
        email: { type: String, required: true, unique: true },
        password: { type: String, required: true },
        username: { type: String },
        bio: { type: String },
        title: { type: String },
        area: { type: String },
        image: {
            type: String,
            default:
                "https://icon-library.com/images/no-profile-pic-icon/no-profile-pic-icon-24.jpg",
        },
        experiences: [
            { type: mongoose.Schema.Types.ObjectId, ref: "Experience" },
        ],
        friends: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
        friendRequests: [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref: "User",
            },
        ],
    },
    { timestamp: true }
);

/**
 * Enyrcyp user password before saving DB
 */
userSchema.pre("save", async function (next) {
    try {
        // const user = this;
        // if (!user.isModified("password")) return next();
        const salt = await bcrypt.genSalt(10);
        this.password = await bcrypt.hash(this.password, salt);
    } catch (error) {
        console.log("Bcryp hash error: ", error);
        next(error);
    }
});

/**
 * Checks entered password and hashed password in DB
 * returns boolean
 * @param {String} enteredPassword
 */
userSchema.methods.isValidPassword = async function (enteredPassword) {
    try {
        return await bcrypt.compare(enteredPassword, this.password);
    } catch (error) {
        console.log("Bcrypt password check error: ", error);
        next(error);
    }
};

const User = mongoose.model("User", userSchema);
module.exports = User;

用于处理用户登录过程的 Passport 中间件

passport.use(
    new LocalStrategy(
        {
            usernameField: "email",
        },
        async (email, password, done) => {
            try {
                const foundUser = await db.User.findOne({ email });
                if (!foundUser) throw new ApiError(400, "Invalid email ");

                const isPasswordsMatched = await foundUser.isValidPassword(
                    password
                );

                if (!isPasswordsMatched)
                    throw new ApiError(400, "Invalid password");

                //Send user if everything  is ok
                done(null, foundUser);
            } catch (error) {
                console.log("Passport local strategy error: ", error);
                done(error, false);
            }
        }
    )
);

标签: javascriptnode.jsmongodbmongoosebcrypt

解决方案


我发现如果我更改散列密码的逻辑,它就可以工作。我删除了 mongoose pre save hook,它在保存数据库之前将哈希添加到密码中。

这是工作结构:

  • 我刚刚将猫鼬钩子转换为方法
/**
 * Enyrcyp user password before saving DB
 */
userSchema.methods.hashPassword = async function () {
    try {
        const salt = await bcrypt.genSalt(10);
        this.password = await bcrypt.hash(this.password, salt);
    } catch (error) {
        console.log("Bcryp hash error: ", error);
        next(error);
    }
};

  • 在将新用户保存到数据库之前,我正在调用 hashPassword 函数。

因此,使用这种结构,我只在用户注册时使用一次 bcrypt。可能文档版本更改正在影响 bcrypt 哈希。所以它现在有效。


推荐阅读