插入前如何散列密码?
How to hash password before inserting?
我正在将 Nest.Js 与 TypeORM 一起使用,我想在保存到数据库之前散列我的密码。
我尝试使用事件装饰器 @BeforeInsert() 但是它对我不起作用,但后来我发现它不起作用,因为我将 DTO 作为输入。
user.controller.ts
@Post()
async create(@Body() data: CreateUserDto, @Res() res) {
// if user already exist
const isUserExist = await this.service.findByEmail(data.email);
if (isUserExist) {
throw new BadRequestException('Email already exist');
}
// insert user
this.service.create(data);
// send response
return res.status(201).json({
statusCode: 201,
message: 'User added Successfully',
});
}
user.service.ts
create(data: CreateUserDto) {
return this.userRepository.save(data)
}
所以,我基本上是使用 DTO 来保存数据。这就是它不起作用的原因。
但我想做的是将 DTO 映射到用户对象。所以,这就是我所做的。
@Post()
async create(@Body() data: CreateUserDto, @Res() res) {
// Create User object
const user = new User();
// Map DTO to User object
for (const [key, value] of Object.entries(data)) {
user[key] = value;
}
// if user already exist
const isUserExist = await this.service.findByEmail(user.email);
if (isUserExist) {
throw new BadRequestException('Email already exist');
}
// insert user
this.service.create(user);
// send response
return res.status(201).json({
statusCode: 201,
message: 'User added Successfully',
});
}
创建-user.dto.ts
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@IsNotEmpty()
@IsString()
@ApiProperty()
readonly firstName: string;
@IsNotEmpty()
@IsString()
@ApiProperty()
readonly lastName: string;
@IsNotEmpty()
@IsString()
@IsEmail()
@ApiProperty()
readonly email: string;
@IsNotEmpty()
@IsString()
@ApiProperty()
readonly password: string;
}
有什么更好的方法吗?因为目前我必须在每个方法中编写代码来映射它。
这是一个有效的方法。
您可以做的是从 create 方法中提取此逻辑并创建某种 Builder 对象以从 DTO 创建 User 对象,反之亦然,并在需要时调用构建器。
我会首先将所有逻辑从我的控制器移到服务中。这将允许您在其他地方重用逻辑(如果有的话)(因为您更喜欢使用该服务 class)。
就个人而言,我会避免编写智能代码,因为它可以节省 2 或 3 行代码。当您以外的其他人必须 review/refactor 时,这将是一种痛苦。写点通俗易懂的吧。
第三,我会避免使用像 beforeInsert 这样神奇的东西。是的,它可能看起来很聪明,但您不清楚通行证是如何生成的。
如果您的实体具有与 DTO 相同的字段,那么拥有 dto 的好处是什么。就我个人而言,我会避免暴露实体的密码 属性。相反,我会在实体中有一个 changePassword(generator: IUserPassGenerator) 方法。至于检查通行证,我会有类似 verifyPass(validator: IPassChecker) 的方法。
我要避免的另一件事是设置器或 public 道具,主要是因为它可能会导致您的实体进入无效状态。在你的情况下,例如其他人可能会使用 md5 哈希更改密码 属性。毕竟,他们甚至可以用未经哈希处理的字符串来更改它。
我们可以使用 'class-transformer'
包
轻松地将 Plain Object Literal
映射到 Class Instances
答案:
async create(@Body() data: CreateUserDto, @Res() res) {
const user = plainToClass(User, data)
}
我正在将 Nest.Js 与 TypeORM 一起使用,我想在保存到数据库之前散列我的密码。
我尝试使用事件装饰器 @BeforeInsert() 但是它对我不起作用,但后来我发现它不起作用,因为我将 DTO 作为输入。
user.controller.ts
@Post()
async create(@Body() data: CreateUserDto, @Res() res) {
// if user already exist
const isUserExist = await this.service.findByEmail(data.email);
if (isUserExist) {
throw new BadRequestException('Email already exist');
}
// insert user
this.service.create(data);
// send response
return res.status(201).json({
statusCode: 201,
message: 'User added Successfully',
});
}
user.service.ts
create(data: CreateUserDto) {
return this.userRepository.save(data)
}
所以,我基本上是使用 DTO 来保存数据。这就是它不起作用的原因。
但我想做的是将 DTO 映射到用户对象。所以,这就是我所做的。
@Post()
async create(@Body() data: CreateUserDto, @Res() res) {
// Create User object
const user = new User();
// Map DTO to User object
for (const [key, value] of Object.entries(data)) {
user[key] = value;
}
// if user already exist
const isUserExist = await this.service.findByEmail(user.email);
if (isUserExist) {
throw new BadRequestException('Email already exist');
}
// insert user
this.service.create(user);
// send response
return res.status(201).json({
statusCode: 201,
message: 'User added Successfully',
});
}
创建-user.dto.ts
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CreateUserDto {
@IsNotEmpty()
@IsString()
@ApiProperty()
readonly firstName: string;
@IsNotEmpty()
@IsString()
@ApiProperty()
readonly lastName: string;
@IsNotEmpty()
@IsString()
@IsEmail()
@ApiProperty()
readonly email: string;
@IsNotEmpty()
@IsString()
@ApiProperty()
readonly password: string;
}
有什么更好的方法吗?因为目前我必须在每个方法中编写代码来映射它。
这是一个有效的方法。
您可以做的是从 create 方法中提取此逻辑并创建某种 Builder 对象以从 DTO 创建 User 对象,反之亦然,并在需要时调用构建器。
我会首先将所有逻辑从我的控制器移到服务中。这将允许您在其他地方重用逻辑(如果有的话)(因为您更喜欢使用该服务 class)。
就个人而言,我会避免编写智能代码,因为它可以节省 2 或 3 行代码。当您以外的其他人必须 review/refactor 时,这将是一种痛苦。写点通俗易懂的吧。
第三,我会避免使用像 beforeInsert 这样神奇的东西。是的,它可能看起来很聪明,但您不清楚通行证是如何生成的。
如果您的实体具有与 DTO 相同的字段,那么拥有 dto 的好处是什么。就我个人而言,我会避免暴露实体的密码 属性。相反,我会在实体中有一个 changePassword(generator: IUserPassGenerator) 方法。至于检查通行证,我会有类似 verifyPass(validator: IPassChecker) 的方法。
我要避免的另一件事是设置器或 public 道具,主要是因为它可能会导致您的实体进入无效状态。在你的情况下,例如其他人可能会使用 md5 哈希更改密码 属性。毕竟,他们甚至可以用未经哈希处理的字符串来更改它。
我们可以使用 'class-transformer'
包
Plain Object Literal
映射到 Class Instances
答案:
async create(@Body() data: CreateUserDto, @Res() res) {
const user = plainToClass(User, data)
}