bcryptjs在mongoose schema的save钩子中不生效,密码未加密问题
你碰到的问题本质是pre('save')中间件全程没有触发,和你用回调还是async/await写加密逻辑无关,所以才会出现console语句不打印、密码明文存储的情况。
绝大多数这类问题都是操作数据的方法不对导致的:mongoose默认仅在调用文档实例的save()方法时触发save中间件,如果你用了insertMany()批量插入数据,或是用findOneAndUpdate()、updateOne()等更新类方法操作数据,默认都不会触发save中间件。
另外注意你当前的Schema配置有问题:password字段加了unique: true约束,这会导致相同密码的用户无法正常入库,业务中不同用户可以使用相同密码,建议删掉这个配置。
解决方法
批量插入用户的场景
方案1:替换insertMany为逐个实例调用save,自然触发save中间件:
// 不要直接调用 User.insertMany(voters) for (const voterItem of voters) { const user = new User(voterItem) await user.save() }
方案2:如果要保留insertMany用法,可以调用时主动开启中间件执行,或是单独编写insertMany中间件处理加密:
// 调用insertMany时传参开启中间件 await User.insertMany(voters, { runMiddleware: true }) // 或是单独定义insertMany钩子处理加密逻辑 userSchema.pre('insertMany', async function(next, docs) { for (const doc of docs) { doc.password = await bcrypt.hash(doc.password, 10) } next() })
更新用户密码的场景
如果是更新密码时不触发加密,同样有两种解决方案:
- 先查询到用户文档实例,修改密码后调用
save方法:
const user = await User.findById(要更新的用户ID) user.password = 新密码 await user.save()
- 单独定义更新类操作的中间件处理加密:
userSchema.pre('findOneAndUpdate', async function(next) { const updateData = this.getUpdate() // 仅当更新内容包含密码字段时做加密 if (updateData.password) { updateData.password = await bcrypt.hash(updateData.password, 10) } next() })
内容的提问来源于stack exchange,提问作者ABDULLOKH MUKHAMMADJONOV
相关产品推荐
相关产品推荐

