You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()
})

更新用户密码的场景

如果是更新密码时不触发加密,同样有两种解决方案:

  1. 先查询到用户文档实例,修改密码后调用save方法:
const user = await User.findById(要更新的用户ID)
user.password = 新密码
await user.save()
  1. 单独定义更新类操作的中间件处理加密:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 18:54:02