门窗专业设计网站,跨境网站建站,wordpress cdn 阿里,外链建设原则创建user模块
先用nest的命令创建一个 user 模块#xff0c;
nest g res user
实现user实体
然后就生成了 user 模块,在它的实体中创建一个用户表user.entity.ts#xff0c;包含 id、用户名、密码,头像、邮箱等等一些字段#xff1a;
Entity(sys_user)
export class Us…创建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: stringExclude({ toPlainOnly: true }) // 输出屏蔽密码Column({ type: varchar, length: 200, nullable: false, comment: 用户登录密码 })public password: stringExclude({ toPlainOnly: true }) // 输出屏蔽盐Column({ type: varchar, length: 200, nullable: false, comment: 盐 })public salt: stringExpose()ApiProperty({ type: String, description: 用户登录账号 })Column({ type: varchar, length: 32, comment: 用户登录账号 })public account: stringExpose()ApiProperty({ type: String, description: 手机号 })Column({ type: varchar, name: phone_num, default: , length: 20, comment: 用户手机号码 })public phoneNum: stringExpose()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): PromiseUserEntity {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: stringApiProperty({ description: 密码 })IsString({ message: password 类型错误正确类型 string })IsNotEmpty({ message: password 不能为空 })password: stringApiProperty({ description: 手机号, required: false })IsString({ message: phoneNum 类型错误正确类型 string })IsMobilePhone(zh-CN, { strictMode: false }, { message: 请输入正确的手机号 })IsOptional()readonly phoneNum?: stringApiProperty({ description: 邮箱, required: false })IsString({ message: email 类型错误正确类型 string })IsEmail()IsOptional()readonly email?: stringApiProperty({ description: 确认密码 })IsString({ message: confirmPassword 类型错误正确类型 string })readonly confirmPassword: stringApiProperty({ description: 头像, required: false })IsString({ message: avatar 类型错误正确类型 string })IsOptional()readonly avatar?: string
}
实现注册逻辑
在user.service.ts写注册的逻辑: /** 创建用户 */async create(dto: CreateUserDto): PromiseUserEntity {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.saveUserEntity(user)})return result}
这里我们对提交的数据做一些判断并对一些账号已存在的情况抛出具体的异常来提醒用户。由于我们不能存储密码的明文这里使用bcryptjs来生成salt然后对密码进行hash之后再将salt和hash值同用户信息一起存入数据库。需要安装依赖库
npm i bcryptjs
npm i --save-dev types/bcryptjs 测试注册接口
模拟一下注册请求 发现注册成功了 返回数据修复
但是这里有个问题返回的数据里既包含了存入数据库的salt和password也包含了仅用于数据验证的confirmPassword。我们要将返回类型修改为PartialUserEntity并且利用 class-transformer将salt、password和confirmPassword排除在外实现修改如下 /** 创建用户 */async create(dto: CreateUserDto): PromisePartialUserEntity {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.saveUserEntity(user)})//去掉salt,password,confirmPasswordreturn plainToInstance(UserEntity, instanceToPlain(result), { excludeExtraneousValues: true })}
再请求一下发现返回接口里不包含敏感信息了