Nest.js权限管理系统开发(七)用户注册

创建user模块

先用nest的命令创建一个 user 模块,

nest g res user

实现user实体

然后就生成了 user 模块,在它的实体中创建一个用户表user.entity.ts,包含 id、用户名、密码,头像、邮箱等等一些字段:

@Entity('sys_user')
export class UserEntity {
  @Expose()
  @ApiProperty({ type: String, description: 'id' })
  @PrimaryGeneratedColumn({ type: 'bigint' })
  public id: string

  @Exclude({ toPlainOnly: true }) // 输出屏蔽密码
  @Column({ type: 'varchar', length: 200, nullable: false, comment: '用户登录密码' })
  public password: string

  @Exclude({ toPlainOnly: true }) // 输出屏蔽盐
  @Column({ type: 'varchar', length: 200, nullable: false, comment: '盐' })
  public salt: string

  @Expose()
  @ApiProperty({ type: String, description: '用户登录账号' })
  @Column({ type: 'varchar', length: 32, comment: '用户登录账号' })
  public account: string

  @Expose()
  @ApiProperty({ type: String, description: '手机号' })
  @Column({ type: 'varchar', name: 'phone_num', default: '', length: 20, comment: '用户手机号码' })
  public phoneNum: string

  @Expose()
  @ApiProperty({ type: String, description: '邮箱' })
  @Column({ type: 'varchar', comment: '邮箱地址', default: '' })
  public email: string

  ....
}

实现注册路由

接下来看一下注册基本逻辑的实现。注册无非就是新增一个用户,在user.controller.ts规定一个路由/user/register接收用户传来的参数

@Post('register')
  @ApiOperation({ summary: '用户注册' })
  @ApiResult(UserEntity)
  @AllowAnon()
  async create(@Body() user: CreateUserDto): Promise<UserEntity> {
    return await this.userService.create(user)
  }

并将CreateUserDto实现如下:

export class CreateUserDto {
  @ApiProperty({ description: '用户账号' })
  @IsString({ message: 'account 类型错误,正确类型 string' })
  @IsNotEmpty({ message: 'account 不能为空' })
  @MinLength(5, { message: '账号至少5个字符' })
  @MaxLength(20, { message: '账号最多20个字符' })
  readonly account: string

  @ApiProperty({ description: '密码' })
  @IsString({ message: 'password 类型错误,正确类型 string' })
  @IsNotEmpty({ message: 'password 不能为空' })
  password: string

  @ApiProperty({ description: '手机号', required: false })
  @IsString({ message: 'phoneNum 类型错误,正确类型 string' })
  @IsMobilePhone('zh-CN', { strictMode: false }, { message: '请输入正确的手机号' })
  @IsOptional()
  readonly phoneNum?: string

  @ApiProperty({ description: '邮箱', required: false })
  @IsString({ message: 'email 类型错误,正确类型 string' })
  @IsEmail()
  @IsOptional()
  readonly email?: string

  @ApiProperty({ description: '确认密码' })
  @IsString({ message: ' confirmPassword 类型错误,正确类型 string' })
  readonly confirmPassword: string

  @ApiProperty({ description: '头像', required: false })
  @IsString({ message: 'avatar 类型错误,正确类型 string' })
  @IsOptional()
  readonly avatar?: string
}

实现注册逻辑

user.service.ts写注册的逻辑:

  /** 创建用户 */
  async create(dto: CreateUserDto): Promise<UserEntity> {
    if (dto.password !== dto.confirmPassword)
      throw new ApiException(ApiErrorCode.USER_PASSWORD_INVALID, '两次输入密码不一致,请重试')
    // 防止重复创建 start
    if (await this.findOneByAccount(dto.account))
      throw new ApiException(ApiErrorCode.USER_CREATE_EXISTING, '帐号已存在,请调整后重新注册!')
    if (await this.userRepo.findOne({ where: { phoneNum: dto.phoneNum } }))
      throw new ApiException(ApiErrorCode.USER_CREATE_EXISTING, '当前手机号已存在,请调整后重新注册')
    if (await this.userRepo.findOne({ where: { email: dto.email } }))
      throw new ApiException(ApiErrorCode.USER_CREATE_EXISTING, '当前邮箱已存在,请调整后重新注册')
    // 防止重复创建 end
    const salt = await genSalt()
    dto.password = await hash(dto.password, salt)
    // plainToInstance  忽略转换 @Exclude 装饰器
    const user = plainToInstance(UserEntity, { salt, ...dto }, { ignoreDecorators: true })
    const result = await this.userManager.transaction(async (transactionalEntityManager) => {
      return await transactionalEntityManager.save<UserEntity>(user)
    })
    return result
  }

这里我们对提交的数据做一些判断,并对一些账号已存在的情况抛出具体的异常,来提醒用户。由于我们不能存储密码的明文,这里使用bcryptjs来生成salt,然后对密码进行hash之后,再将salt和hash值同用户信息一起存入数据库。需要安装依赖库:

npm i bcryptjs
npm i --save-dev @types/bcryptjs

测试注册接口

模拟一下注册请求:

发现注册成功了:

返回数据修复

但是这里有个问题,返回的数据里既包含了存入数据库的salt和password,也包含了仅用于数据验证的confirmPassword。我们要将返回类型修改为Partial<UserEntity>,并且利用 class-transformer将salt、password和confirmPassword排除在外,实现修改如下:

  /** 创建用户 */
  async create(dto: CreateUserDto): Promise<Partial<UserEntity>> {
    if (dto.password !== dto.confirmPassword)
      throw new ApiException(ApiErrorCode.USER_PASSWORD_INVALID, '两次输入密码不一致,请重试')
    // 防止重复创建 start
    if (await this.findOneByAccount(dto.account))
      throw new ApiException(ApiErrorCode.USER_CREATE_EXISTING, '帐号已存在,请调整后重新注册!')
    if (await this.userRepo.findOne({ where: { phoneNum: dto.phoneNum } }))
      throw new ApiException(ApiErrorCode.USER_CREATE_EXISTING, '当前手机号已存在,请调整后重新注册')
    if (await this.userRepo.findOne({ where: { email: dto.email } }))
      throw new ApiException(ApiErrorCode.USER_CREATE_EXISTING, '当前邮箱已存在,请调整后重新注册')
    // 防止重复创建 end
    const salt = await genSalt()
    dto.password = await hash(dto.password, salt)
    // plainToInstance  忽略转换 @Exclude 装饰器
    const user = plainToInstance(UserEntity, { salt, ...dto }, { ignoreDecorators: true })
    const result = await this.userManager.transaction(async (transactionalEntityManager) => {
      return await transactionalEntityManager.save<UserEntity>(user)
    })
    //去掉salt,password,confirmPassword
    return plainToInstance(UserEntity, instanceToPlain(result), { excludeExtraneousValues: true })
  }

再请求一下,发现返回接口里不包含敏感信息了:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/412470.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

部署VUE+SpringBoot+nginx项目

本文是前端是vite element-plus 后端 springBoot 部署整个项目主要分为3个步骤&#xff0c; 1. 部署nginx&#xff0c;主要是配置nginx.conf 2.打包前端代码 3.打包后端代码 1.安装nginx 安装手顺&#xff1a; linux安装nginx_linux安装nginx需要gcc还是gcc-c-CSDN…

什么品牌的护眼台灯比较好用?全网最全护眼台灯避坑指南(内含五大品牌推荐)

在家长们意识到学习过程中优质的光线环境对保护孩子视力的重要性时&#xff0c;如何在众多护眼台灯当中如何选出合格又好用的产品却成为了一大头疼问题。市场上充斥着一些无良厂家生产的劣质产品&#xff0c;很容易误导普通消费者。为了帮助大家避开这些陷阱&#xff0c;我决定…

编译链接库路径设置

/etc/ld.so.conf和LD_LIBRARY_PATH具有同等的作用&#xff0c;都是程序运行时链接的库。 可通过export LIBRARY_PATH~/test/Lib:$LIBRARY_PATH 添加动态库搜索路径&#xff0c;通过printenv | grep LIBRARY查看是否添加成功。

FL Studio All Plugins Edition2024中文完整版Win/Mac

FL Studio All Plugins Edition&#xff0c;常被誉为数字音频工作站&#xff08;DAW&#xff09;的佼佼者&#xff0c;是音乐制作人和声音工程师钟爱的工具。它集音频录制、编辑、混音以及MIDI制作为一体&#xff0c;为用户提供了从创作到最终作品输出的完整工作流程。这个版本…

PDF文件转换为图片

现在确实有很多线上的工具可以把pdf文件转为图片&#xff0c;比如smallpdf等等&#xff0c;都很好用。但我们有时会碰到一些敏感数据&#xff0c;或者要批量去转&#xff0c;那么需要自己写脚本来实现&#xff0c;以下脚本可以提供这个功能~ def pdf2img(pdf_dir, result_path…

Escalate_Linux(3)--通过读取密码文件shadow来破解root用户的口令实现提权

通过读取密码文件shadow来破解root用户的口令实现提权 通过读取密码文件/etc/shadow来破解root用户的口令 ls -l /etc/shadow 普通用户无查看shadow权限 echo "cat /etc/shadow" >/tmp/ls ​ chmod 755 /tmp/ls ​ export PATH/tmp:$PATH ​ /home/user5/script…

U-Mail邮件系统反垃圾病毒解决方案

随着互联网的快速发展和广泛应用&#xff0c;人类正逐步地从工业社会迈入信息社会&#xff0c;网络也已经越来越成为生产经营活动的重要场所。例如电子邮件就已经企业内外部信息交流的重要工具&#xff0c;它的应用还可以提高企业办公效率&#xff0c;利于企业信息流通的系统化…

【Flink精讲】Flink反压调优

Flink 网络流控及反压的介绍&#xff1a; Apache Flink学习网 反压的理解 简单来说&#xff0c; Flink 拓扑中每个节点&#xff08;Task&#xff09;间的数据都以阻塞队列的方式传输&#xff0c;下游来不及消费导致队列被占满后&#xff0c;上游的生产也会被阻塞&#xff0c;…

泪滴中的关怀:新生儿泪腺堵塞及细心照料

引言 新生儿的眼睛是他们与世界沟通的桥梁&#xff0c;而泪腺则是这座桥梁上的一颗璀璨明珠。然而&#xff0c;有时这颗明珠可能会遇到困难&#xff0c;泪腺堵塞是一个常见的问题。在这篇文章中&#xff0c;我们将探讨新生儿泪腺堵塞的注意事项&#xff0c;以及如何细心照料宝…

算法价值6-梯度下降

梯度下降算法(gradient descent algorithm)是一种常用的优化算法,用于寻找函数的最小值点或最小化损失函数。它的核心思想是通过迭代调整参数的值,使目标函数的值逐渐趋于最小值。 具体来说,梯度下降算法的步骤如下: 1. 初始化参数 首先,需要初始化待优化的参数,可以…

vue3自定义实现悬浮固定按钮组件

目录 一、需求描述二、代码解读三、结果展示 一、需求描述 需要5个固定的悬浮圆&#xff0c;居于页面的右侧。鼠标悬浮在圆上面会显示对应的文字提示其中包含返回顶部悬浮圆&#xff0c;当页面滑至底部时出现&#xff0c;点击页面滑到顶部。点击按钮会给出弹窗 二、代码解读…

Fastapi进阶用法,路径参数,路由分发,查询参数等详解

文章目录 1、路径操作1.路径操作装饰器1.tags 标签2.summary 接口描述的总结信息3.describe: 接口信息的详细描述4.response_description&#xff1a;响应描述5.deprecated&#xff1a;接口是否废弃&#xff0c;默认是False 2.fastapi路由分发include_router 2、请求与响应2.1、…

Web APIs 3 事件

Web APIs 3 事件 一、事件流事件捕获事件冒泡阻止冒泡解绑事件鼠标经过事件的区别两种注册事件的区别 二、事件委托阻止默认行为 三、其他事件① 页面加载事件② 元素滚动事件滚动到指定的坐标 ③ 页面尺寸事件 元素尺寸与位置① 元素在页面中的位置② 元素尺寸 一、事件流 事…

ABBYY FineReader16文档转换、PDF管理与文档比较功能介绍

ABBYY FineReader 16作为一款OCR和PDF一体化程序&#xff0c;其强大的功能使得文档处理变得简单高效。在众多功能中&#xff0c;文档转换、PDF管理和文档比较这三大功能尤为突出&#xff0c;成为了众多企业和个人用户的首选工具。 ABBYY Finereader 16-安装包下载如下&#xff…

【接口测试】POST请求提交数据的三种方式及Postman实现

1. 什么是POST请求&#xff1f; POST请求是HTPP协议中一种常用的请求方法&#xff0c;它的使用场景是向客户端向服务器提交数据&#xff0c;比如登录、注册、添加等场景。另一种常用的请求方法是GET&#xff0c;它的使用场景是向服务器获取数据。 2. POST请求提交数据的常见编…

YOLOv6、YOLOv7、YOLOv8网络结构图(清晰版)

承接上一篇博客&#xff1a;YOLOv3、YOLOv4、YOLOv5、YOLOx的网络结构图(清晰版)_yolox网络结构图-CSDN博客 1. YOLOv6网络结构图 2. YOLOv7网络结构图 3. YOLOv8网络结构图

一文讲清DTO、BO、PO、VO

DTO、BO、PO、VO是什么&#xff1f; 在后端开发中&#xff0c;比如传统的MVC架构和现在流行的DDD架构&#xff0c;经常会使用到下列几种对象的概念 DTO (Data Transfer Object) 数据传输对象&#xff1a; DTO设计模式用于将数据从服务端传输到客户端&#xff0c;或者在不同的…

【SVN】使用TortoiseGit删除Git分支

使用TortoiseGit删除Git分支 前言 平时我在进行开发的时候&#xff0c;比如需要开发一个新功能&#xff0c;这里以蘑菇博客开发服务网关-gateway功能为例 一般我都会在原来master分支的基础上&#xff0c;然后拉取一个新的分支【gateway】&#xff0c;然后在 gateway分支上进…

数据安全-动态加密(不同敏感字段使用不同的加密算法-MySQL、Oracle版本)

动态数据加密 动态加密&#xff08;也称实时加密&#xff0c;透明加密等&#xff0c;其英文名为encrypt on-the-fly&#xff09;&#xff0c;是指数据在使用过程中自动对数据进行加密或解密操作&#xff0c;无需用户的干预&#xff0c;合法用户在使用加密的文件前&#xff0c;…

天翼云登录参数JavaSrcipt逆向

天翼云登录参数 password 、comParam_curTime、comParam_seqCode、comParam_signature JavaSrcipt逆向 目标网站 https://m.ctyun.cn/wap/main/auth/login?redirect/my 目标参数 要逆向的有 password、comParam_curTime、comParam_seqCode、comParam_signature 四个参数 …