【问题标题】:How to hash password before inserting?如何在插入之前对密码进行哈希处理?
【发布时间】:2020-05-23 22:26:42
【问题描述】:

我正在使用带有 TypeORM 的 Nest.Js,并且我想在保存到数据库之前对我的密码进行哈希处理。

我尝试使用事件装饰器 @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',
    });
  }

create-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;
}

有没有更好的方法呢?因为目前我必须在每个方法中编写代码来映射它。

【问题讨论】:

    标签: node.js typescript nestjs dto typeorm


    【解决方案1】:

    这是一种有效的方法。

    您可以做的是从 create 方法中提取此逻辑并创建某种 Builder 对象以从 DTO 创建 User 对象,反之亦然,并在您需要的地方调用 builder。

    【讨论】:

    • 感谢您的快速回复,但您能否提供一个代码示例,因为我无法实现它。
    【解决方案2】:

    我首先将所有逻辑从我的控制器移到服务中。如果有的话,这将允许您在其他地方重用逻辑(因为您更喜欢拥有该服务类)。

    就我个人而言,我会避免编写智能代码,因为它可以为我节省 2 或 3 行代码。当您以外的其他人必须审查/重构时,这将是一件很痛苦的事情。写一些通俗易懂的东西就行了。

    第三,我会避免使用像 beforeInsert 这样的魔法。是的,它可能看起来很聪明,但您并不清楚通行证是如何生成的。

    1. 如果您的实体与您的 DTO 具有相同的字段,那么拥有 dto 的好处是什么。我个人会避免暴露实体的密码属性。相反,我将在实体中有一个 changePassword(generator: IUserPassGenerator) 方法。至于检查通行证,我会有类似于 verifyPass(validator: IPassChecker) 的方法。

    2. 我要避免的另一件事是 setter 或 public props,主要是因为它可能会导致您的实体进入无效状态。在你的情况下,例如其他人可能会使用 md5 哈希更改密码属性。毕竟,他们甚至可以使用未散列的字符串来更改它。

    【讨论】:

    • @BogdonUngureanu 1.) 好的,我现在已经按逻辑放置在服务中。 3.) 我不知道为什么我不应该使用像 BeforeInsert() 这样的魔法东西。它是框架基础的一部分,所以为什么不使用它。 4.) 不,我的 DTO 与我的实体具有不同的属性,但即使它具有相同的属性,我也认为我需要使用它,因为我在 DTO 中应用了约束进行验证。
    • BeforeInsert 和类似的东西用于扩展框架的行为,而不是应用程序逻辑。 :) 至于 dto,我的建议是在您的实体上拥有一个接受该 dto 的工厂方法。我给你的建议是基于 DDD 原则的。这样想,如果不再维护nestjs会怎样?如果您决定迁移到另一个框架,则必须重写所有内容。
    【解决方案3】:

    我们可以使用'class-transformer'包轻松地将Plain Object Literal映射到Class Instances

    答案:

    async create(@Body() data: CreateUserDto, @Res() res) {
    
    const user = plainToClass(User, data)
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-16
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多