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, '两次输入密码不一致,请重试')// 防止重复创建 startif (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, '当前邮箱已存在,请调整后重新注册')// 防止重复创建 endconst 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, '两次输入密码不一致,请重试')// 防止重复创建 startif (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, '当前邮箱已存在,请调整后重新注册')// 防止重复创建 endconst 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,confirmPasswordreturn plainToInstance(UserEntity, instanceToPlain(result), { excludeExtraneousValues: true })}

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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux操作系统】死锁 | 预防、避免死锁

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;Linux系列专栏&#xff1a;Linux基础 &#x1f525; 给大家…

SSM框架学习笔记07 | Spring MVC入门

文章目录 1. HTTP协议2. Spring MVC2.1. 三层架构2.2. MVC&#xff08;解决表现层的问题&#xff09;2.3. 核心组件 3. Thymeleaf3.1. 模板引擎3.2. Thymeleaf3.3. 常用语法 代码 1. HTTP协议 网址&#xff1a;https://www.ietf.org/ &#xff08;官网网址&#xff09; https:…

探索 Sora 视频模型背后的基础算法

2024年2月16日&#xff0c;OpenAI发布Sora文生视频模型&#xff0c;一石激起千层浪&#xff0c;迅速刷屏爆火于整个AI圈。一方面&#xff0c;Sora从文本、图像迈向视频大模型&#xff0c;这可以说是通向通用人工智能的里程碑事件&#xff1b;另一方面&#xff0c;训练和推理需求…

ETL数据仓库的使用方式

一、ETL的过程 在 ETL 过程中&#xff0c;数据从源系统中抽取&#xff08;Extract&#xff09;&#xff0c;经过各种转换&#xff08;Transform&#xff09;操作&#xff0c;最后加载&#xff08;Load&#xff09;到目标数据仓库中。以下是 ETL 数仓流程的基本步骤&#xff1a…

系统找不到xinput1_3.dll怎么办?试试这五种解决方法轻松搞定

在计算机系统运行过程中&#xff0c;当我们遭遇“找不到xinput1_3.dll”这一错误提示时&#xff0c;实际上正面临一个软件兼容性、系统组件缺失以及游戏或应用程序无法正常启动的关键问题。深入探究这一现象&#xff0c;我们会发现它可能引发一系列连带问题&#xff0c;例如某些…

Vue:vue的安装与环境的搭建

文章目录 环境搭建安装node.js&#xff08;比较简单&#xff09;安装Vue脚手架初始化启动 环境搭建 安装node.js&#xff08;比较简单&#xff09; 首先要安装node.js&#xff0c;进入官网下载即可。 更改安装路径&#xff0c;保持默认配置&#xff0c;一直点击下一步安装即可…

Jmeter系列(2)目录介绍

目录 Jmeter目录介绍bin目录docsextrasliblicensesprintable_docs Jmeter目录介绍 在学习Jmeter之前&#xff0c;需要先对工具的目录有些了解&#xff0c;也会方便后续的学习 bin目录 examplesCSV目录中有CSV样例jmeter.batwindow 启动文件jmeter.shMac/linux的启动文件jmete…

设计并实现一个并发安全的LRU(Least Recently Used,最近最少使用)缓存结构

文章目录 前言实战演示写在最后 前言 相信很多人都使用过LinkedHashMap&#xff0c;LinkedHashMap中的removeEldestEntry可以删除老旧的元素&#xff0c;我们可以以此来实现一个LRU缓存结构&#xff0c;并结合java中JUC包中的各种多线程锁机制来保证多线程安全。 以下是我遇见…

YOLOv9来了!实时目标检测新SOTA

先上一把网上的测试效果对比: YOLOv9架构图 速度论文 代码&#xff1a;GitHub - WongKinYiu/yolov9: Implementation of paper - YOLOv9: Learning What You Want to Learn Using Programmable Gradient Information 论文&#xff1a;[2402.13616] YOLOv9: Learning What You…

x-cmd pkg | g - 功能和交互更为丰富的 `ls` 替代方案

目录 简介首次用户功能特点竞品和相关作品进一步阅读 简介 g 是一项用 Go 开发的、功能和交互更为丰富的 ls 替代方案。它拥有 100 多个功能选项&#xff0c;主要是通过各式图标、各种布局选项和 git status 集成来增强视觉效果&#xff0c;并且支持多种输出格式&#xff0c;如…

在having、select子句中使用子查询

目录 在having子句中使用子查询 统计出部门平均工资高于公司平均工资的部门编号、平均工资、部门人数 在select子句中使用子查询 查询每个员工的编号、姓名、职位、部门名称 Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 在havin…

内存函数(C语言进阶)

目录 前言 1、memcpy 2、memmove 3、memcmp 4、memset 结语 前言 本篇介绍了C语言中的内存函数&#xff0c;内存函数&#xff0c;顾名思义就是处理内存的函数。 1、memcpy memcpy&#xff1a;内存拷贝函数。 相对于strcpy只能拷贝字符串来讲&#xff0c;memcpy能拷…