typescript - Nest.js/Mongoose: Hvorfor blir ikke min pre save-hook utløst?
Jeg har nettopp begynt å jobbe med Nest.js, og så langt har det gått greit. Imidlertid har jeg støtt på et problem der min mongoose pre save hook i User-skjemaet ikke blir utløst. Dette burde være enkelt, men av en eller annen grunn blir passordet lagret i sin vanlige form i stedet for å bli hashed. Hva skjer?
Ett lite problem til - hvordan definerer jeg et felt som refererer til en annen skjema når jeg bruker @Prop-dekoratører? Profilfeltet skal være av mongoose.schema.types.objectid, som ganske enkelt ville være profile: { type: mongoose.Schema.Types.ObjectId, ref: 'Profile' } når man arbeider uten dekoratører.
Nedenfor er de relevante utdragene.
Brukerskjema
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);
Brukermodul
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 {}
Brukertjeneste
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),
};
}
}
Svar #1
Jeg vet at dette spørsmålet har blitt stilt for lenge siden, men for folk som møter dette problemet igjen, her er hvordan man fikser det.
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;
}
i stedet for å kalle next() manuelt, kan du bruke en funksjon som returnerer et løfte. Spesielt kan du bruke async/await.
Svar #2
Du kan ikke bruke async i kombinasjon med next()
schema.pre<User>('save', function (next) {
const user = this;
console.log(user)
next();
});
Bør fungere
