From fc1d4453ceea0d59b3abaf08bb47cd5c4956d2c2 Mon Sep 17 00:00:00 2001 From: minorcell Date: Thu, 1 May 2025 02:23:34 +0800 Subject: [PATCH 1/2] feat: add user profile fields for avatar, nickname and phone number --- src/usercenter/dto/create-usercenter.dto.ts | 4 ++++ src/usercenter/entities/usercenter.entity.ts | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/usercenter/dto/create-usercenter.dto.ts b/src/usercenter/dto/create-usercenter.dto.ts index fc6e259..6e2e0de 100644 --- a/src/usercenter/dto/create-usercenter.dto.ts +++ b/src/usercenter/dto/create-usercenter.dto.ts @@ -33,4 +33,8 @@ export class CreateUsercenterDto { @Min(0, { message: '性别值必须大于等于0' }) @Max(2, { message: '性别值必须小于等于2' }) sex?: number; // 性别,0未知,1男,2女 + + @IsOptional() + @IsString() + avatar?: string; // 用户头像 } diff --git a/src/usercenter/entities/usercenter.entity.ts b/src/usercenter/entities/usercenter.entity.ts index d8499db..3dc2e9c 100644 --- a/src/usercenter/entities/usercenter.entity.ts +++ b/src/usercenter/entities/usercenter.entity.ts @@ -124,6 +124,13 @@ export class UserEntity { }) userPassword: string; // 用户密码 + @Column({ + type: 'varchar', + name: 'avatar', + default: '' + }) + avatar: string; // 头像 + // 关联文章,一个用户可以有多篇文章 @OneToMany(() => ArticleEntity, (article) => article.user) articles: ArticleEntity[]; From ffc85e3d217340137af202e7b7fa1dd577d02f46 Mon Sep 17 00:00:00 2001 From: minorcell Date: Thu, 1 May 2025 16:52:01 +0800 Subject: [PATCH 2/2] Add user authentication and profile management services for login flow --- src/auth/auth.service.ts | 64 +++++++++++++++++++--------- src/usercenter/usercenter.service.ts | 15 ++++--- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 2046a61..998acce 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -1,5 +1,5 @@ import { UsercenterService } from './../usercenter/usercenter.service'; -import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { Injectable, UnauthorizedException, NotFoundException, BadRequestException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; @Injectable() @@ -10,32 +10,51 @@ export class AuthService { ) {} async signIn(username: string, pass: string): Promise { - const user = await this.usersService.findOne(username); + try { + const user = await this.usersService.findOne(username); - // 直接使用用户密码进行验证 - if (user?.userPassword !== pass) { - throw new UnauthorizedException(); - } + // 直接使用用户密码进行验证 + if (user?.userPassword !== pass) { + throw new UnauthorizedException('用户名或密码错误'); + } - const payload = { sub: user.userId, username: user.userName }; - const refreshPayload = { sub: user.userId }; - - return { - userId: user.userId, - access_token: await this.jwtService.signAsync(payload, { - expiresIn: '7d', - }), - refresh_token: await this.jwtService.signAsync(refreshPayload, { - expiresIn: '7d', - }), - }; + const payload = { sub: user.userId, username: user.userName }; + const refreshPayload = { sub: user.userId }; + + return { + userId: user.userId, + access_token: await this.jwtService.signAsync(payload, { + expiresIn: '7d', + }), + refresh_token: await this.jwtService.signAsync(refreshPayload, { + expiresIn: '7d', + }), + }; + } catch (error) { + // 捕获findOne方法抛出的NotFoundException异常并将其转换为UnauthorizedException + // 这样用户名不存在和密码错误都返回相同的401状态码 + if (error instanceof NotFoundException) { + throw new UnauthorizedException('用户名或密码错误'); + } + throw error; + } } async refreshToken(refresh_token: string) { try { + // 如果refresh_token为空或无效格式,返回400错误 + if (!refresh_token || typeof refresh_token !== 'string') { + throw new BadRequestException('无效的refresh_token格式'); + } + + // 验证token const decoded = await this.jwtService.verifyAsync(refresh_token); + // 确保用户存在 const user = await this.usersService.findOne(decoded.sub); + if (!user) { + throw new NotFoundException('用户不存在'); + } const access_token = await this.jwtService.signAsync( { id: decoded.sub, userName: user.userName }, @@ -47,8 +66,13 @@ export class AuthService { { expiresIn: '7d' }, ); return { refresh_token: newRefresh_token, access_token }; - } catch { - throw new UnauthorizedException('refresh_token已过期'); + } catch (error) { + // 区分不同类型的错误 + if (error instanceof BadRequestException || error instanceof NotFoundException) { + throw error; // 重新抛出原始错误 + } + // JWT相关错误统一处理为401未授权 + throw new UnauthorizedException('refresh_token无效或已过期'); } } } diff --git a/src/usercenter/usercenter.service.ts b/src/usercenter/usercenter.service.ts index 10cb4c3..14fa27e 100644 --- a/src/usercenter/usercenter.service.ts +++ b/src/usercenter/usercenter.service.ts @@ -2,6 +2,8 @@ import { BadRequestException, Injectable, InternalServerErrorException, + NotFoundException, + ConflictException } from '@nestjs/common'; import { CreateUsercenterDto } from './dto/create-usercenter.dto'; import { UpdateUsercenterDto } from './dto/update-usercenter.dto'; @@ -29,7 +31,7 @@ export class UsercenterService { where: [{ userName: createUsercenterDto.userName }], }); if (existingUser) { - throw new BadRequestException('用户名已存在'); + throw new ConflictException('用户名已存在'); } // 检查邮箱是否已存在 @@ -37,7 +39,7 @@ export class UsercenterService { where: [{ userEmail: createUsercenterDto.userEmail }], }); if (existingEmail) { - throw new BadRequestException('邮箱已被注册'); + throw new ConflictException('邮箱已被注册'); } await validateOrReject(createUsercenterDto); @@ -74,8 +76,9 @@ export class UsercenterService { take: limit, // 每页记录数 order: { createTime: 'DESC' }, // 按创建时间倒序排列 }); + // 如果没有数据,返回空数组,不抛出异常 if (total === 0) { - throw new InternalServerErrorException(`数量为0`); + return { total: 0, data: [], message: '没有数据', status: 200 }; } return { total, data, message: '查询成功', status: 200 }; @@ -146,7 +149,7 @@ export class UsercenterService { }); } if (!user) { - throw new InternalServerErrorException(`未找到匹配 ${identifier} 的记录`); + throw new NotFoundException(`未找到匹配 ${identifier} 的记录`); } return user; @@ -155,7 +158,7 @@ export class UsercenterService { async update(id: number, updateUsercenterDto: UpdateUsercenterDto) { const user = await this.userRepository.findOneBy({ userId: id }); if (!user) { - throw new InternalServerErrorException(`用户 ID 为 ${id} 的记录不存在`); + throw new NotFoundException(`用户 ID 为 ${id} 的记录不存在`); } // 合并更新数据 @@ -172,7 +175,7 @@ export class UsercenterService { async remove(id: number) { const user = await this.userRepository.findOneBy({ userId: id }); if (!user) { - throw new InternalServerErrorException(`用户 ID 为 ${id} 的记录不存在`); + throw new NotFoundException(`用户 ID 为 ${id} 的记录不存在`); } const data = await this.userRepository.delete(id);