forked from datawhale/whale-town-end
范围:src/gateway/auth/, src/business/auth/, src/app.module.ts 涉及文件: - 新增:src/gateway/auth/ 目录及所有文件 - 移动:Controller、Guard、Decorator、DTO从business层移至gateway层 - 修改:src/business/auth/index.ts(移除Gateway层组件导出) - 修改:src/app.module.ts(使用AuthGatewayModule替代AuthModule) 主要改进: - 明确Gateway层和Business层的职责边界 - Controller、Guard、Decorator属于Gateway层职责 - Business层专注于业务逻辑和服务 - 符合分层架构设计原则
454 lines
11 KiB
TypeScript
454 lines
11 KiB
TypeScript
/**
|
||
* 登录业务数据传输对象
|
||
*
|
||
* 功能描述:
|
||
* - 定义登录相关API的请求数据结构
|
||
* - 提供数据验证规则和错误提示
|
||
* - 确保API接口的数据格式一致性
|
||
*
|
||
* 职责分离:
|
||
* - 专注于数据结构定义和验证规则
|
||
* - 提供Swagger文档生成支持
|
||
* - 确保类型安全和数据完整性
|
||
*
|
||
* 最近修改:
|
||
* - 2026-01-07: 代码规范优化 - 文件夹扁平化,移除单文件文件夹结构
|
||
* - 2026-01-07: 代码规范优化 - 更新注释规范,修正作者信息
|
||
*
|
||
* @author moyin
|
||
* @version 1.0.2
|
||
* @since 2025-12-17
|
||
* @lastModified 2026-01-07
|
||
*/
|
||
|
||
import {
|
||
IsString,
|
||
IsEmail,
|
||
IsPhoneNumber,
|
||
IsNotEmpty,
|
||
Length,
|
||
IsOptional,
|
||
Matches,
|
||
IsNumberString
|
||
} from 'class-validator';
|
||
import { ApiProperty } from '@nestjs/swagger';
|
||
|
||
/**
|
||
* 登录请求DTO
|
||
*/
|
||
export class LoginDto {
|
||
/**
|
||
* 登录标识符
|
||
* 支持用户名、邮箱或手机号登录
|
||
*/
|
||
@ApiProperty({
|
||
description: '登录标识符,支持用户名、邮箱或手机号',
|
||
example: 'testuser',
|
||
minLength: 1,
|
||
maxLength: 100
|
||
})
|
||
@IsString({ message: '登录标识符必须是字符串' })
|
||
@IsNotEmpty({ message: '登录标识符不能为空' })
|
||
@Length(1, 100, { message: '登录标识符长度需在1-100字符之间' })
|
||
identifier: string;
|
||
|
||
/**
|
||
* 密码
|
||
*/
|
||
@ApiProperty({
|
||
description: '用户密码',
|
||
example: 'password123',
|
||
minLength: 1,
|
||
maxLength: 128
|
||
})
|
||
@IsString({ message: '密码必须是字符串' })
|
||
@IsNotEmpty({ message: '密码不能为空' })
|
||
@Length(1, 128, { message: '密码长度需在1-128字符之间' })
|
||
password: string;
|
||
}
|
||
|
||
/**
|
||
* 注册请求DTO
|
||
*/
|
||
export class RegisterDto {
|
||
/**
|
||
* 用户名
|
||
*/
|
||
@ApiProperty({
|
||
description: '用户名,只能包含字母、数字和下划线',
|
||
example: 'testuser',
|
||
minLength: 1,
|
||
maxLength: 50,
|
||
pattern: '^[a-zA-Z0-9_]+$'
|
||
})
|
||
@IsString({ message: '用户名必须是字符串' })
|
||
@IsNotEmpty({ message: '用户名不能为空' })
|
||
@Length(1, 50, { message: '用户名长度需在1-50字符之间' })
|
||
@Matches(/^[a-zA-Z0-9_]+$/, { message: '用户名只能包含字母、数字和下划线' })
|
||
username: string;
|
||
|
||
/**
|
||
* 密码
|
||
*/
|
||
@ApiProperty({
|
||
description: '密码,必须包含字母和数字,长度8-128字符',
|
||
example: 'password123',
|
||
minLength: 8,
|
||
maxLength: 128
|
||
})
|
||
@IsString({ message: '密码必须是字符串' })
|
||
@IsNotEmpty({ message: '密码不能为空' })
|
||
@Length(8, 128, { message: '密码长度需在8-128字符之间' })
|
||
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '密码必须包含字母和数字' })
|
||
password: string;
|
||
|
||
/**
|
||
* 昵称
|
||
*/
|
||
@ApiProperty({
|
||
description: '用户昵称',
|
||
example: '测试用户',
|
||
minLength: 1,
|
||
maxLength: 50
|
||
})
|
||
@IsString({ message: '昵称必须是字符串' })
|
||
@IsNotEmpty({ message: '昵称不能为空' })
|
||
@Length(1, 50, { message: '昵称长度需在1-50字符之间' })
|
||
nickname: string;
|
||
|
||
/**
|
||
* 邮箱(可选)
|
||
*/
|
||
@ApiProperty({
|
||
description: '邮箱地址(可选)',
|
||
example: 'test@example.com',
|
||
required: false
|
||
})
|
||
@IsOptional()
|
||
@IsEmail({}, { message: '邮箱格式不正确' })
|
||
email?: string;
|
||
|
||
/**
|
||
* 手机号(可选)
|
||
*/
|
||
@ApiProperty({
|
||
description: '手机号码(可选)',
|
||
example: '+8613800138000',
|
||
required: false
|
||
})
|
||
@IsOptional()
|
||
@IsPhoneNumber(null, { message: '手机号格式不正确' })
|
||
phone?: string;
|
||
|
||
/**
|
||
* 邮箱验证码(当提供邮箱时必填)
|
||
*/
|
||
@ApiProperty({
|
||
description: '邮箱验证码,当提供邮箱时必填',
|
||
example: '123456',
|
||
pattern: '^\\d{6}$',
|
||
required: false
|
||
})
|
||
@IsOptional()
|
||
@IsString({ message: '验证码必须是字符串' })
|
||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
||
email_verification_code?: string;
|
||
}
|
||
|
||
/**
|
||
* GitHub OAuth登录请求DTO
|
||
*/
|
||
export class GitHubOAuthDto {
|
||
/**
|
||
* GitHub用户ID
|
||
*/
|
||
@ApiProperty({
|
||
description: 'GitHub用户ID',
|
||
example: '12345678',
|
||
minLength: 1,
|
||
maxLength: 100
|
||
})
|
||
@IsString({ message: 'GitHub ID必须是字符串' })
|
||
@IsNotEmpty({ message: 'GitHub ID不能为空' })
|
||
@Length(1, 100, { message: 'GitHub ID长度需在1-100字符之间' })
|
||
github_id: string;
|
||
|
||
/**
|
||
* 用户名
|
||
*/
|
||
@ApiProperty({
|
||
description: 'GitHub用户名',
|
||
example: 'octocat',
|
||
minLength: 1,
|
||
maxLength: 50
|
||
})
|
||
@IsString({ message: '用户名必须是字符串' })
|
||
@IsNotEmpty({ message: '用户名不能为空' })
|
||
@Length(1, 50, { message: '用户名长度需在1-50字符之间' })
|
||
username: string;
|
||
|
||
/**
|
||
* 昵称
|
||
*/
|
||
@ApiProperty({
|
||
description: 'GitHub显示名称',
|
||
example: 'The Octocat',
|
||
minLength: 1,
|
||
maxLength: 50
|
||
})
|
||
@IsString({ message: '昵称必须是字符串' })
|
||
@IsNotEmpty({ message: '昵称不能为空' })
|
||
@Length(1, 50, { message: '昵称长度需在1-50字符之间' })
|
||
nickname: string;
|
||
|
||
/**
|
||
* 邮箱(可选)
|
||
*/
|
||
@ApiProperty({
|
||
description: 'GitHub邮箱地址(可选)',
|
||
example: 'octocat@github.com',
|
||
required: false
|
||
})
|
||
@IsOptional()
|
||
@IsEmail({}, { message: '邮箱格式不正确' })
|
||
email?: string;
|
||
|
||
/**
|
||
* 头像URL(可选)
|
||
*/
|
||
@ApiProperty({
|
||
description: 'GitHub头像URL(可选)',
|
||
example: 'https://github.com/images/error/octocat_happy.gif',
|
||
required: false
|
||
})
|
||
@IsOptional()
|
||
@IsString({ message: '头像URL必须是字符串' })
|
||
avatar_url?: string;
|
||
}
|
||
|
||
/**
|
||
* 忘记密码请求DTO
|
||
*/
|
||
export class ForgotPasswordDto {
|
||
/**
|
||
* 邮箱或手机号
|
||
*/
|
||
@ApiProperty({
|
||
description: '邮箱或手机号',
|
||
example: 'test@example.com',
|
||
minLength: 1,
|
||
maxLength: 100
|
||
})
|
||
@IsString({ message: '标识符必须是字符串' })
|
||
@IsNotEmpty({ message: '邮箱或手机号不能为空' })
|
||
@Length(1, 100, { message: '标识符长度需在1-100字符之间' })
|
||
identifier: string;
|
||
}
|
||
|
||
/**
|
||
* 重置密码请求DTO
|
||
*/
|
||
export class ResetPasswordDto {
|
||
/**
|
||
* 邮箱或手机号
|
||
*/
|
||
@ApiProperty({
|
||
description: '邮箱或手机号',
|
||
example: 'test@example.com',
|
||
minLength: 1,
|
||
maxLength: 100
|
||
})
|
||
@IsString({ message: '标识符必须是字符串' })
|
||
@IsNotEmpty({ message: '邮箱或手机号不能为空' })
|
||
@Length(1, 100, { message: '标识符长度需在1-100字符之间' })
|
||
identifier: string;
|
||
|
||
/**
|
||
* 验证码
|
||
*/
|
||
@ApiProperty({
|
||
description: '6位数字验证码',
|
||
example: '123456',
|
||
pattern: '^\\d{6}$'
|
||
})
|
||
@IsString({ message: '验证码必须是字符串' })
|
||
@IsNotEmpty({ message: '验证码不能为空' })
|
||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
||
verification_code: string;
|
||
|
||
/**
|
||
* 新密码
|
||
*/
|
||
@ApiProperty({
|
||
description: '新密码,必须包含字母和数字,长度8-128字符',
|
||
example: 'newpassword123',
|
||
minLength: 8,
|
||
maxLength: 128
|
||
})
|
||
@IsString({ message: '新密码必须是字符串' })
|
||
@IsNotEmpty({ message: '新密码不能为空' })
|
||
@Length(8, 128, { message: '新密码长度需在8-128字符之间' })
|
||
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '新密码必须包含字母和数字' })
|
||
new_password: string;
|
||
}
|
||
|
||
/**
|
||
* 修改密码请求DTO
|
||
*/
|
||
export class ChangePasswordDto {
|
||
/**
|
||
* 用户ID
|
||
* 实际应用中应从JWT令牌中获取,这里为了演示放在请求体中
|
||
*/
|
||
@ApiProperty({
|
||
description: '用户ID(实际应用中应从JWT令牌中获取)',
|
||
example: '1'
|
||
})
|
||
@IsNumberString({}, { message: '用户ID必须是数字字符串' })
|
||
@IsNotEmpty({ message: '用户ID不能为空' })
|
||
user_id: string;
|
||
|
||
/**
|
||
* 旧密码
|
||
*/
|
||
@ApiProperty({
|
||
description: '当前密码',
|
||
example: 'oldpassword123',
|
||
minLength: 1,
|
||
maxLength: 128
|
||
})
|
||
@IsString({ message: '旧密码必须是字符串' })
|
||
@IsNotEmpty({ message: '旧密码不能为空' })
|
||
@Length(1, 128, { message: '旧密码长度需在1-128字符之间' })
|
||
old_password: string;
|
||
|
||
/**
|
||
* 新密码
|
||
*/
|
||
@ApiProperty({
|
||
description: '新密码,必须包含字母和数字,长度8-128字符',
|
||
example: 'newpassword123',
|
||
minLength: 8,
|
||
maxLength: 128
|
||
})
|
||
@IsString({ message: '新密码必须是字符串' })
|
||
@IsNotEmpty({ message: '新密码不能为空' })
|
||
@Length(8, 128, { message: '新密码长度需在8-128字符之间' })
|
||
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '新密码必须包含字母和数字' })
|
||
new_password: string;
|
||
}
|
||
|
||
/**
|
||
* 邮箱验证请求DTO
|
||
*/
|
||
export class EmailVerificationDto {
|
||
/**
|
||
* 邮箱地址
|
||
*/
|
||
@ApiProperty({
|
||
description: '邮箱地址',
|
||
example: 'test@example.com'
|
||
})
|
||
@IsEmail({}, { message: '邮箱格式不正确' })
|
||
@IsNotEmpty({ message: '邮箱不能为空' })
|
||
email: string;
|
||
|
||
/**
|
||
* 验证码
|
||
*/
|
||
@ApiProperty({
|
||
description: '6位数字验证码',
|
||
example: '123456',
|
||
pattern: '^\\d{6}$'
|
||
})
|
||
@IsString({ message: '验证码必须是字符串' })
|
||
@IsNotEmpty({ message: '验证码不能为空' })
|
||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
||
verification_code: string;
|
||
}
|
||
|
||
/**
|
||
* 发送邮箱验证码请求DTO
|
||
*/
|
||
export class SendEmailVerificationDto {
|
||
/**
|
||
* 邮箱地址
|
||
*/
|
||
@ApiProperty({
|
||
description: '邮箱地址',
|
||
example: 'test@example.com'
|
||
})
|
||
@IsEmail({}, { message: '邮箱格式不正确' })
|
||
@IsNotEmpty({ message: '邮箱不能为空' })
|
||
email: string;
|
||
}
|
||
|
||
/**
|
||
* 验证码登录请求DTO
|
||
*/
|
||
export class VerificationCodeLoginDto {
|
||
/**
|
||
* 登录标识符
|
||
* 支持邮箱或手机号登录
|
||
*/
|
||
@ApiProperty({
|
||
description: '登录标识符,支持邮箱或手机号',
|
||
example: 'test@example.com',
|
||
minLength: 1,
|
||
maxLength: 100
|
||
})
|
||
@IsString({ message: '登录标识符必须是字符串' })
|
||
@IsNotEmpty({ message: '登录标识符不能为空' })
|
||
@Length(1, 100, { message: '登录标识符长度需在1-100字符之间' })
|
||
identifier: string;
|
||
|
||
/**
|
||
* 验证码
|
||
*/
|
||
@ApiProperty({
|
||
description: '6位数字验证码',
|
||
example: '123456',
|
||
pattern: '^\\d{6}$'
|
||
})
|
||
@IsString({ message: '验证码必须是字符串' })
|
||
@IsNotEmpty({ message: '验证码不能为空' })
|
||
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
|
||
verification_code: string;
|
||
}
|
||
|
||
/**
|
||
* 发送登录验证码请求DTO
|
||
*/
|
||
export class SendLoginVerificationCodeDto {
|
||
/**
|
||
* 登录标识符
|
||
* 支持邮箱或手机号
|
||
*/
|
||
@ApiProperty({
|
||
description: '登录标识符,支持邮箱或手机号',
|
||
example: 'test@example.com',
|
||
minLength: 1,
|
||
maxLength: 100
|
||
})
|
||
@IsString({ message: '登录标识符必须是字符串' })
|
||
@IsNotEmpty({ message: '登录标识符不能为空' })
|
||
@Length(1, 100, { message: '登录标识符长度需在1-100字符之间' })
|
||
identifier: string;
|
||
}
|
||
|
||
/**
|
||
* 刷新令牌请求DTO
|
||
*/
|
||
export class RefreshTokenDto {
|
||
/**
|
||
* 刷新令牌
|
||
*/
|
||
@ApiProperty({
|
||
description: 'JWT刷新令牌',
|
||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
||
minLength: 1
|
||
})
|
||
@IsString({ message: '刷新令牌必须是字符串' })
|
||
@IsNotEmpty({ message: '刷新令牌不能为空' })
|
||
refresh_token: string;
|
||
} |