【问题标题】:Mongoose userSchema.pre("save") Not Working猫鼬 userSchema.pre("save") 不工作
【发布时间】:2021-02-10 05:30:50
【问题描述】:

我编写了一个方法来更新我的应用程序中的用户,并且在那里一切正常。另外,我写了一些代码,在文档保存之前触发,它不能正常工作。

代码的重点是确定用户是否修改了密码。如果他们没有,只需调用 next()。如果他们这样做了,bcrypt 将对密码进行哈希处理。

这是我正在更新的控制器中的代码:

// @desc    Update user by ID
// @route   PUT /api/users/:id
// @access  Private
const updateUserById = asyncHandler(async (req, res) => {
    // Destructure body content from request
    const {
        firstName,
        lastName,
        username,
        email,
        role,
        manager,
        learningStyle,
        departments,
        facility,
        company,
        isActive,
    } = req.body;
    // Search the database for the user
    const user = await User.findById(req.params.id);
    // Check to ensure the user was found. Else, respond with 404 error
    if (user) {
        // Update information accordingly
        user.firstName = firstName || user.firstName;
        user.lastName = lastName || user.lastName;
        user.username = username || user.username;
        user.email = email || user.email;
        user.role = role || user.role;
        user.manager = manager || user.manager;
        user.learningStyle = learningStyle || user.learningStyle;
        user.departments = departments || user.departments;
        user.facility = facility || user.facility;
        user.company = company || user.company;
        user.isActive = isActive === undefined ? user.isActive : isActive;
        // Save user to the database with updated information
        const updatedUser = await user.save();
        // Send the updated user to the client
        res.json(updatedUser);
    } else {
        res.status(404);
        throw new Error("User not found");
    }
});

这是我的用户模型代码:

import mongoose from "mongoose";
import bcrypt from "bcryptjs";

const userSchema = mongoose.Schema(
    {
        firstName: {
            // The user's first name
            required: true,
            type: String,
            trim: true,
        },
        lastName: {
            // The user's last name
            required: true,
            type: String,
            trim: true,
        },
        username: {
            // The user's username - user can create their own
            required: true,
            type: String,
            unique: true,
            lowercase: true,
        },
        email: {
            // The user's email
            required: false,
            trim: true,
            lowercase: true,
            unique: true,
            type: String,
        },
        password: {
            // The user's encrypted password (bcrypt hash)
            required: true,
            type: String,
        },
        role: {
            // The user's role - drives what they're able to do within the application
            required: true,
            type: mongoose.Schema.Types.ObjectId,
            ref: "Role",
        },
        manager: {
            // The user's manager
            type: mongoose.Schema.Types.ObjectId,
            required: false,
            ref: "User",
        },
        learningStyle: {
            // The user's learning style (after assessment is taken)
            type: mongoose.Schema.Types.ObjectId,
            required: false,
            ref: "LearningStyle",
        },
        departments: [
            // The departments the user belongs to (used to drive what the user sees)
            // Example: Finishing, Shipping, Printing
            {
                type: mongoose.Schema.Types.ObjectId,
                required: false,
                ref: "Department",
            },
        ],
        facility: {
            // The facility the user works at. Example: Austin Facility
            type: mongoose.Schema.Types.ObjectId,
            required: false,
            ref: "Facility",
        },
        company: {
            // The company the user works for. Example: Microsoft
            type: mongoose.Schema.Types.ObjectId,
            required: true,
            ref: "Company",
        },
        isActive: {
            required: true,
            type: Boolean,
            default: true,
        },
    },
    { timestamps: true }
);

// Match user's password using bcrypt
userSchema.methods.matchPassword = async function (enteredPassword) {
    return await bcrypt.compare(enteredPassword, this.password);
};

// Generate user's encrypted password on save
userSchema.pre("save", async function (next) {
    // Check to see if password is modified. If it is, encrypt it. If not, execute next();
    if (!this.isModified("password")) {
        console.log("Does this run?");
        next();
    }
    console.log("Does this run as well?");
    const salt = await bcrypt.genSalt(10);
    this.password = await bcrypt.hash(this.password, salt);
});

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

export default User;

我有:

  • 添加了两个控制台日志,均在模型中触发(参见 userSchema.pre("save"))。
  • 试图通过检查密码是否被修改来防止加密触发
  • 尝试删除整个用户集合并重新开始
  • 课程中的另一个应用程序使用完全相同的方法运行良好

请注意,我的控制器中根本没有更新密码。然而,每次我使用 Postman 发送 PUT 请求并修改名称时,密码都会再次被散列并且两个控制台日志都会触发。

【问题讨论】:

    标签: javascript node.js mongodb mongoose


    【解决方案1】:

    “保存”中间件正在调用next(),但继续完成该功能。使用returnelse 保护其余代码。

    userSchema.pre("save", async function (next) {
        // Check to see if password is modified. If it is, encrypt it. If not, execute next();
        if (!this.isModified("password")) {
            // Finish here
            return next();
        }
        const salt = await bcrypt.genSalt(10);
        this.password = await bcrypt.hash(this.password, salt);
    });
    

    【讨论】:

    • 我应该将它添加到我使用相同方法的另一个项目中,一切正常。不知道那里发生了什么。
    • next 会让猫鼬继续并保存文档。也许这是一场比赛?如果文档在 bcrypt 完成盐/哈希之前写入,那没关系。你只是很幸运,或者没有注意到它何时发生在其他项目中。
    • 非常感谢,马特!我想我在课程中遵循的代码有点缺陷。非常感谢额外的清晰度和学习机会。
    猜你喜欢
    • 2016-06-14
    • 1970-01-01
    • 2017-03-28
    • 2021-07-14
    • 2018-07-22
    • 1970-01-01
    • 2020-09-03
    • 2018-05-02
    • 2017-05-26
    相关资源
    最近更新 更多