Nest.js/Mongoose:为什么我的 pre save 钩子没有被触发?

6

我刚开始使用 Nest.js,到目前为止一切顺利。然而,我遇到了一个问题,就是在 User 模式中的 mongoose pre save hook 没有被触发。这应该很简单,但不知何故密码以明文形式保存而不是哈希。这是怎么回事?

还有一个小问题 - 当使用 @Prop 装饰器时,如何定义一个引用另一个模式的字段?在没有装饰器的情况下,profile 字段应该是 mongoose.schema.types.objectid,即 profile: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' }。

以下是相关片段。

User 模式

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema({
  timestamps: true,
})
export class User extends Document {
  @Prop({ required: true })
  fullname: string;

  @Prop({ required: true, unique: true })
  username: string;

  @Prop({ required: true, unique: true, lowercase: true })
  email: string;

  @Prop({ required: true })
  password: string;

  @Prop({ required: true, ref: 'Profile' })
  profile: string

  @Prop({ required: true, enum: ['admin', 'basic' ]})
  role: string
}

export const UserSchema = SchemaFactory.createForClass(User);

用户模块

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import * as bcrypt from 'bcrypt';

import { User, UserSchema } from './user.model';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [
    MongooseModule.forFeatureAsync([
      {
        name: User.name,
        useFactory: () => {
          const schema = UserSchema;

          schema.pre<User>('save', async function (next: Function) {
            const user = this;

            const salt = await bcrypt.genSalt(10);
            const hashedPassword = await bcrypt.hash(user.password, salt);

            user.password = hashedPassword;

            next();
          });

          schema.methods.comparePasswords = async function (submittedPassword) {
            const user = this;

            await bcrypt.compare(submittedPassword, user.password);
          };

          return schema;
        },
      },
    ]),
  ],
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

用户服务

import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { JwtService } from '@nestjs/jwt';

import { UsersService } from '../users/users.service';
import { ProfilesService } from '../profiles/profiles.service';
import { User } from '../users/user.model';

@Injectable()
export class AuthService {
  constructor(
    @InjectModel(User.name) private readonly userModel: Model<User>,
    private usersService: UsersService,
    private profilesService: ProfilesService,
    private jwtService: JwtService
  ) {}

  async signup(signupData): Promise<any> {
    const foundUser = await this.userModel.findOne({ email: signupData.email });

    if (foundUser) {
      throw new HttpException(
        'Email is already in use',
        HttpStatus.BAD_REQUEST
      );
    }

    const createdProfile = await this.profilesService.createProfile();

    const createdUser = await this.userModel.create({
      ...signupData,
      profile: createdProfile._id,
      role: 'basic',
    });

    const createdUserCopy = { ...createdUser.toObject() };

    delete createdUserCopy.password;
    delete createdUserCopy.__v;

    const payload = {
      username: createdUser.username,
      sub: createdUser._id,
    };

    return {
      user: createdUserCopy,
      token: this.jwtService.sign(payload),
    };
  }
}
2个回答

3

我知道这个问题很久以前就被问过了,但对于那些再次遇到此问题的人,以下是如何解决它的方法。

useFactory: () => {
          const schema = UserSchema;

          schema.pre<User>('save', async function () {
            const user = this;

            const salt = await bcrypt.genSalt(10);
            const hashPassword = await bcrypt.hash(user.password, salt);

            user.salt = salt;
            user.password = hashPassword;
          });
          return schema;
        }

不需要手动调用 next(),您可以使用返回 Promise 的函数。特别是您可以使用 async/await。


0

您不能将asyncnext()结合使用。

schema.pre<User>('save', function (next) {
  const user = this;
  console.log(user)
  next();
});

应该可以工作


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接