版本升级:1.0.0 1.1.0 新功能: - 验证码登录功能完整实现 - 支持邮箱和手机号验证码登录 - 新增2个API接口(总计23个) 文档更新: - Swagger API文档版本更新 - OpenAPI规范文档更新 - 手动API文档版本更新 - 添加v1.1.0版本更新日志 技术改进: - 完善验证码相关错误处理 - 优化API响应格式一致性 - 增强测试覆盖率 更新内容: - package.json: 1.0.0 1.1.0 - Swagger配置: 1.0.0 1.1.0 - OpenAPI文档: 1.0.0 1.1.0 - 应用状态接口: 1.0.0 1.1.0 - API文档: 添加v1.1.0更新日志
2342 lines
58 KiB
Markdown
2342 lines
58 KiB
Markdown
# Pixel Game Server API接口文档
|
||
|
||
## 概述
|
||
|
||
本文档描述了像素游戏服务器的完整API接口,包括用户认证、管理员后台、应用状态等功能。
|
||
|
||
**基础URL**: `http://localhost:3000`
|
||
**API文档地址**: `http://localhost:3000/api-docs`
|
||
**项目名称**: Pixel Game Server
|
||
**版本**: 1.0.0
|
||
|
||
## 通用响应格式
|
||
|
||
所有API接口都遵循统一的响应格式:
|
||
|
||
```json
|
||
{
|
||
"success": boolean,
|
||
"data": object | null,
|
||
"message": string,
|
||
"error_code": string | null
|
||
}
|
||
```
|
||
|
||
### 字段说明
|
||
|
||
- `success`: 请求是否成功
|
||
- `data`: 响应数据(成功时返回)
|
||
- `message`: 响应消息
|
||
- `error_code`: 错误代码(失败时返回)
|
||
|
||
## 接口分类
|
||
|
||
### 1. 应用状态接口 (App)
|
||
- `GET /` - 获取应用状态
|
||
|
||
### 2. 用户认证接口 (Auth)
|
||
- `POST /auth/login` - 用户登录
|
||
- `POST /auth/verification-code-login` - 验证码登录
|
||
- `POST /auth/send-login-verification-code` - 发送登录验证码
|
||
- `POST /auth/register` - 用户注册
|
||
- `POST /auth/github` - GitHub OAuth登录
|
||
- `POST /auth/forgot-password` - 发送密码重置验证码
|
||
- `POST /auth/reset-password` - 重置密码
|
||
- `PUT /auth/change-password` - 修改密码
|
||
- `POST /auth/send-email-verification` - 发送邮箱验证码
|
||
- `POST /auth/verify-email` - 验证邮箱验证码
|
||
- `POST /auth/resend-email-verification` - 重新发送邮箱验证码
|
||
- `POST /auth/debug-verification-code` - 调试验证码信息(开发环境)
|
||
- `POST /auth/debug-clear-throttle` - 清除限流记录(开发环境)
|
||
|
||
### 3. 管理员接口 (Admin)
|
||
- `POST /admin/auth/login` - 管理员登录
|
||
- `GET /admin/users` - 获取用户列表
|
||
- `GET /admin/users/:id` - 获取用户详情
|
||
- `POST /admin/users/:id/reset-password` - 重置用户密码
|
||
- `GET /admin/logs/runtime` - 获取运行日志
|
||
- `GET /admin/logs/archive` - 下载日志压缩包
|
||
|
||
### 4. 用户管理接口 (User Management)
|
||
- `PUT /admin/users/:id/status` - 修改用户状态
|
||
- `POST /admin/users/batch-status` - 批量修改用户状态
|
||
- `GET /admin/users/status-stats` - 获取用户状态统计
|
||
|
||
## 接口列表
|
||
|
||
### 应用状态接口
|
||
|
||
#### 1. 获取应用状态
|
||
|
||
**接口地址**: `GET /`
|
||
|
||
**功能描述**: 返回应用的基本运行状态信息,用于健康检查和监控
|
||
|
||
#### 请求参数
|
||
|
||
无
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"service": "Pixel Game Server",
|
||
"version": "1.0.0",
|
||
"status": "running",
|
||
"timestamp": "2025-12-23T10:00:00.000Z",
|
||
"uptime": 3600,
|
||
"environment": "development",
|
||
"storage_mode": "memory"
|
||
}
|
||
```
|
||
|
||
| 字段名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| service | string | 服务名称 |
|
||
| version | string | 服务版本 |
|
||
| status | string | 运行状态 (running/starting/stopping/error) |
|
||
| timestamp | string | 当前时间戳 |
|
||
| uptime | number | 运行时间(秒) |
|
||
| environment | string | 运行环境 (development/production/test) |
|
||
| storage_mode | string | 存储模式 (database/memory) |
|
||
|
||
### 用户认证接口
|
||
|
||
#### 1. 用户登录
|
||
|
||
**接口地址**: `POST /auth/login`
|
||
|
||
**功能描述**: 用户登录,支持用户名、邮箱或手机号登录
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"identifier": "testuser",
|
||
"password": "password123"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| identifier | string | 是 | 登录标识符,支持用户名、邮箱或手机号 |
|
||
| password | string | 是 | 用户密码 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user": {
|
||
"id": "1",
|
||
"username": "testuser",
|
||
"nickname": "测试用户",
|
||
"email": "test@example.com",
|
||
"phone": "+8613800138000",
|
||
"avatar_url": "https://example.com/avatar.jpg",
|
||
"role": 1,
|
||
"created_at": "2025-12-17T10:00:00.000Z"
|
||
},
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"is_new_user": false,
|
||
"message": "登录成功"
|
||
},
|
||
"message": "登录成功"
|
||
}
|
||
```
|
||
|
||
**失败响应** (401):
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "用户名或密码错误",
|
||
"error_code": "LOGIN_FAILED"
|
||
}
|
||
```
|
||
|
||
#### 1.1 验证码登录
|
||
|
||
**接口地址**: `POST /auth/verification-code-login`
|
||
|
||
**功能描述**: 使用邮箱或手机号和验证码进行登录,无需密码
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"identifier": "test@example.com",
|
||
"verification_code": "123456"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| identifier | string | 是 | 登录标识符(邮箱或手机号) |
|
||
| verification_code | string | 是 | 6位数字验证码 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user": {
|
||
"id": "1",
|
||
"username": "testuser",
|
||
"nickname": "测试用户",
|
||
"email": "test@example.com",
|
||
"phone": "+8613800138000",
|
||
"avatar_url": "https://example.com/avatar.jpg",
|
||
"role": 1,
|
||
"created_at": "2025-12-17T10:00:00.000Z"
|
||
},
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"is_new_user": false,
|
||
"message": "验证码登录成功"
|
||
},
|
||
"message": "验证码登录成功"
|
||
}
|
||
```
|
||
|
||
**失败响应** (401):
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "验证码错误或已过期",
|
||
"error_code": "VERIFICATION_CODE_LOGIN_FAILED"
|
||
}
|
||
```
|
||
|
||
**可能的错误码**:
|
||
- `VERIFICATION_CODE_LOGIN_FAILED`: 验证码错误或已过期
|
||
- `USER_NOT_FOUND`: 用户不存在
|
||
- `EMAIL_NOT_VERIFIED`: 邮箱未验证(邮箱登录时)
|
||
- `INVALID_IDENTIFIER`: 无效的邮箱或手机号格式
|
||
|
||
#### 1.2 发送登录验证码
|
||
|
||
**接口地址**: `POST /auth/send-login-verification-code`
|
||
|
||
**功能描述**: 向用户邮箱或手机发送登录验证码
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"identifier": "test@example.com"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| identifier | string | 是 | 邮箱或手机号 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "验证码发送成功",
|
||
"data": {
|
||
"sent_to": "test@example.com",
|
||
"expires_in": 300
|
||
}
|
||
}
|
||
```
|
||
|
||
**测试模式响应** (206):
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "测试模式:验证码已生成但未真实发送",
|
||
"error_code": "TEST_MODE_ONLY",
|
||
"data": {
|
||
"verification_code": "123456",
|
||
"sent_to": "test@example.com",
|
||
"expires_in": 300,
|
||
"is_test_mode": true
|
||
}
|
||
}
|
||
```
|
||
|
||
**失败响应** (404):
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "用户不存在",
|
||
"error_code": "SEND_LOGIN_CODE_FAILED"
|
||
}
|
||
```
|
||
|
||
#### 2. 用户注册
|
||
|
||
**接口地址**: `POST /auth/register`
|
||
|
||
**功能描述**: 创建新用户账户
|
||
|
||
**重要说明**:
|
||
- 如果提供邮箱,必须先调用发送验证码接口获取验证码
|
||
- 注册时会按以下顺序进行检查:
|
||
1. 首先检查用户名是否已存在
|
||
2. 检查邮箱是否已存在(如果提供)
|
||
3. 检查手机号是否已存在(如果提供)
|
||
4. 最后验证邮箱验证码(如果提供邮箱)
|
||
- 这样确保验证码不会因为用户已存在而被无效消费
|
||
- 注册成功返回201,失败返回400
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"username": "testuser",
|
||
"password": "password123",
|
||
"nickname": "测试用户",
|
||
"email": "test@example.com",
|
||
"email_verification_code": "123456"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| username | string | 是 | 用户名,只能包含字母、数字和下划线,长度1-50字符 |
|
||
| password | string | 是 | 密码,必须包含字母和数字,长度8-128字符 |
|
||
| nickname | string | 是 | 用户昵称,长度1-50字符 |
|
||
| email | string | 否 | 邮箱地址(如果提供,必须先获取验证码) |
|
||
| phone | string | 否 | 手机号码 |
|
||
| email_verification_code | string | 条件必填 | 邮箱验证码,提供邮箱时必填 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (201):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user": {
|
||
"id": "2",
|
||
"username": "testuser",
|
||
"nickname": "测试用户",
|
||
"email": "test@example.com",
|
||
"phone": "+8613800138000",
|
||
"avatar_url": null,
|
||
"role": 1,
|
||
"created_at": "2025-12-17T10:00:00.000Z"
|
||
},
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"is_new_user": true,
|
||
"message": "注册成功"
|
||
},
|
||
"message": "注册成功"
|
||
}
|
||
```
|
||
|
||
**失败响应** (400):
|
||
|
||
**用户名已存在**:
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "用户名已存在",
|
||
"error_code": "REGISTER_FAILED"
|
||
}
|
||
```
|
||
|
||
**邮箱已存在**:
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "邮箱已存在",
|
||
"error_code": "REGISTER_FAILED"
|
||
}
|
||
```
|
||
|
||
**手机号已存在**:
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "手机号已存在",
|
||
"error_code": "REGISTER_FAILED"
|
||
}
|
||
```
|
||
|
||
**邮箱验证码相关错误**:
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "提供邮箱时必须提供邮箱验证码",
|
||
"error_code": "REGISTER_FAILED"
|
||
}
|
||
```
|
||
|
||
**频率限制响应** (429):
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "注册请求过于频繁,请5分钟后再试",
|
||
"error_code": "TOO_MANY_REQUESTS",
|
||
"throttle_info": {
|
||
"limit": 10,
|
||
"window_seconds": 300,
|
||
"current_requests": 10,
|
||
"reset_time": "2025-12-24T11:26:41.136Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 3. GitHub OAuth登录
|
||
|
||
**接口地址**: `POST /auth/github`
|
||
|
||
**功能描述**: 使用GitHub账户登录或注册
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"github_id": "12345678",
|
||
"username": "octocat",
|
||
"nickname": "The Octocat",
|
||
"email": "octocat@github.com",
|
||
"avatar_url": "https://github.com/images/error/octocat_happy.gif"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| github_id | string | 是 | GitHub用户ID |
|
||
| username | string | 是 | GitHub用户名 |
|
||
| nickname | string | 是 | GitHub显示名称 |
|
||
| email | string | 否 | GitHub邮箱地址 |
|
||
| avatar_url | string | 否 | GitHub头像URL |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user": {
|
||
"id": "3",
|
||
"username": "octocat",
|
||
"nickname": "The Octocat",
|
||
"email": "octocat@github.com",
|
||
"phone": null,
|
||
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
||
"role": 1,
|
||
"created_at": "2025-12-17T10:00:00.000Z"
|
||
},
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"is_new_user": true,
|
||
"message": "GitHub账户绑定成功"
|
||
},
|
||
"message": "GitHub账户绑定成功"
|
||
}
|
||
```
|
||
|
||
#### 4. 发送密码重置验证码
|
||
|
||
**接口地址**: `POST /auth/forgot-password`
|
||
|
||
**功能描述**: 向用户邮箱或手机发送密码重置验证码
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"identifier": "test@example.com"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| identifier | string | 是 | 邮箱或手机号 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"verification_code": "123456"
|
||
},
|
||
"message": "验证码已发送,请查收"
|
||
}
|
||
```
|
||
|
||
**注意**: 实际应用中不应返回验证码,这里仅用于演示。
|
||
|
||
#### 5. 重置密码
|
||
|
||
**接口地址**: `POST /auth/reset-password`
|
||
|
||
**功能描述**: 使用验证码重置用户密码
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"identifier": "test@example.com",
|
||
"verification_code": "123456",
|
||
"new_password": "newpassword123"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| identifier | string | 是 | 邮箱或手机号 |
|
||
| verification_code | string | 是 | 6位数字验证码 |
|
||
| new_password | string | 是 | 新密码,必须包含字母和数字,长度8-128字符 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "密码重置成功"
|
||
}
|
||
```
|
||
|
||
#### 6. 修改密码
|
||
|
||
**接口地址**: `PUT /auth/change-password`
|
||
|
||
**功能描述**: 用户修改自己的密码(需要提供旧密码)
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"user_id": "1",
|
||
"old_password": "oldpassword123",
|
||
"new_password": "newpassword123"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| user_id | string | 是 | 用户ID(实际应用中应从JWT令牌中获取) |
|
||
| old_password | string | 是 | 当前密码 |
|
||
| new_password | string | 是 | 新密码,必须包含字母和数字,长度8-128字符 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "密码修改成功"
|
||
}
|
||
```
|
||
|
||
#### 7. 发送邮箱验证码
|
||
|
||
**接口地址**: `POST /auth/send-email-verification`
|
||
|
||
**功能描述**: 向指定邮箱发送验证码,用于注册时的邮箱验证
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"email": "test@example.com"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| email | string | 是 | 邮箱地址 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"verification_code": "123456",
|
||
"is_test_mode": false
|
||
},
|
||
"message": "验证码已发送,请查收"
|
||
}
|
||
```
|
||
|
||
**测试模式响应** (206):
|
||
```json
|
||
{
|
||
"success": false,
|
||
"data": {
|
||
"verification_code": "059174",
|
||
"is_test_mode": true
|
||
},
|
||
"message": "⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。",
|
||
"error_code": "TEST_MODE_ONLY"
|
||
}
|
||
```
|
||
|
||
#### 8. 验证邮箱验证码
|
||
|
||
**接口地址**: `POST /auth/verify-email`
|
||
|
||
**功能描述**: 使用验证码验证邮箱
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"email": "test@example.com",
|
||
"verification_code": "123456"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| email | string | 是 | 邮箱地址 |
|
||
| verification_code | string | 是 | 6位数字验证码 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "邮箱验证成功"
|
||
}
|
||
```
|
||
|
||
#### 9. 重新发送邮箱验证码
|
||
|
||
**接口地址**: `POST /auth/resend-email-verification`
|
||
|
||
**功能描述**: 重新向指定邮箱发送验证码
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"email": "test@example.com"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| email | string | 是 | 邮箱地址 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"verification_code": "123456",
|
||
"is_test_mode": false
|
||
},
|
||
"message": "验证码已重新发送,请查收"
|
||
}
|
||
```
|
||
|
||
#### 10. 调试验证码信息
|
||
|
||
**接口地址**: `POST /auth/debug-verification-code`
|
||
|
||
**功能描述**: 获取验证码的详细调试信息(仅开发环境使用)
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"email": "test@example.com"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| email | string | 是 | 邮箱地址 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"email": "test@example.com",
|
||
"verification_code": "123456",
|
||
"expires_at": "2025-12-23T10:15:00.000Z",
|
||
"created_at": "2025-12-23T10:00:00.000Z"
|
||
},
|
||
"message": "调试信息获取成功"
|
||
}
|
||
```
|
||
|
||
#### 11. 清除限流记录
|
||
|
||
**接口地址**: `POST /auth/debug-clear-throttle`
|
||
|
||
**功能描述**: 清除所有限流记录(仅开发环境使用)
|
||
|
||
**注意**: 此接口用于开发测试,清除所有IP的频率限制记录
|
||
|
||
#### 请求参数
|
||
|
||
无
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "限流记录已清除"
|
||
}
|
||
```
|
||
|
||
### 管理员接口
|
||
|
||
**注意**:所有管理员接口都需要在 Header 中携带 `Authorization: Bearer <token>`,且用户角色必须为管理员 (role=9)。
|
||
|
||
#### 1. 管理员登录
|
||
|
||
**接口地址**: `POST /admin/auth/login`
|
||
|
||
**功能描述**: 管理员登录,仅允许 role=9 的账户登录后台
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"identifier": "admin",
|
||
"password": "Admin123456"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| identifier | string | 是 | 登录标识符(用户名/邮箱/手机号) |
|
||
| password | string | 是 | 密码 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"admin": {
|
||
"id": "1",
|
||
"username": "admin",
|
||
"nickname": "管理员",
|
||
"role": 9
|
||
},
|
||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"expires_at": 1766102400000
|
||
},
|
||
"message": "管理员登录成功"
|
||
}
|
||
```
|
||
|
||
#### 2. 获取用户列表
|
||
|
||
**接口地址**: `GET /admin/users`
|
||
|
||
**功能描述**: 分页获取所有注册用户列表
|
||
|
||
#### 请求参数
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| limit | number | 否 | 每页数量,默认100 |
|
||
| offset | number | 否 | 偏移量,默认0 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"users": [
|
||
{
|
||
"id": "1",
|
||
"username": "user1",
|
||
"nickname": "小明",
|
||
"email": "user1@example.com",
|
||
"email_verified": false,
|
||
"phone": "+8613800138000",
|
||
"avatar_url": "https://example.com/avatar.png",
|
||
"role": 1,
|
||
"created_at": "2025-12-19T00:00:00.000Z",
|
||
"updated_at": "2025-12-19T00:00:00.000Z"
|
||
}
|
||
],
|
||
"limit": 100,
|
||
"offset": 0
|
||
},
|
||
"message": "用户列表获取成功"
|
||
}
|
||
```
|
||
|
||
#### 3. 获取用户详情
|
||
|
||
**接口地址**: `GET /admin/users/:id`
|
||
|
||
**功能描述**: 获取指定用户的详细信息
|
||
|
||
#### 请求参数
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | string | 是 | 用户ID(路径参数) |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user": {
|
||
"id": "1",
|
||
"username": "user1",
|
||
"nickname": "小明",
|
||
"email": "user1@example.com",
|
||
"email_verified": false,
|
||
"phone": "+8613800138000",
|
||
"avatar_url": "https://example.com/avatar.png",
|
||
"role": 1,
|
||
"created_at": "2025-12-19T00:00:00.000Z",
|
||
"updated_at": "2025-12-19T00:00:00.000Z"
|
||
}
|
||
},
|
||
"message": "用户信息获取成功"
|
||
}
|
||
```
|
||
|
||
#### 4. 重置用户密码
|
||
|
||
**接口地址**: `POST /admin/users/:id/reset-password`
|
||
|
||
**功能描述**: 管理员强制重置指定用户的密码
|
||
|
||
#### 请求参数
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | string | 是 | 用户ID(路径参数) |
|
||
| new_password | string | 是 | 新密码(至少8位,包含字母和数字) |
|
||
|
||
```json
|
||
{
|
||
"new_password": "NewPass1234"
|
||
}
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"message": "密码重置成功"
|
||
}
|
||
```
|
||
|
||
#### 5. 获取运行日志
|
||
|
||
**接口地址**: `GET /admin/logs/runtime`
|
||
|
||
**功能描述**: 从 logs/ 目录读取最近的日志行
|
||
|
||
#### 请求参数
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| lines | number | 否 | 返回行数,默认200,最大2000 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"file": "dev.log",
|
||
"updated_at": "2025-12-19T19:10:15.000Z",
|
||
"lines": [
|
||
"[2025-12-19 19:10:15] INFO: Server started",
|
||
"[2025-12-19 19:10:16] INFO: Database connected"
|
||
]
|
||
},
|
||
"message": "运行日志获取成功"
|
||
}
|
||
```
|
||
|
||
#### 6. 下载日志压缩包
|
||
|
||
**接口地址**: `GET /admin/logs/archive`
|
||
|
||
**功能描述**: 将 logs/ 目录打包为 tar.gz 并下载
|
||
|
||
#### 请求参数
|
||
|
||
无
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
- Content-Type: `application/gzip`
|
||
- Content-Disposition: `attachment; filename="logs-2025-12-23T10-00-00-000Z.tar.gz"`
|
||
- 返回二进制流(tar.gz 文件)
|
||
|
||
### 用户管理接口
|
||
|
||
**注意**:所有用户管理接口都需要管理员权限,需要在 Header 中携带 `Authorization: Bearer <token>`。
|
||
|
||
#### 1. 修改用户状态
|
||
|
||
**接口地址**: `PUT /admin/users/:id/status`
|
||
|
||
**功能描述**: 管理员修改指定用户的账户状态,支持激活、锁定、禁用等操作
|
||
|
||
#### 请求参数
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| id | string | 是 | 用户ID(路径参数) |
|
||
| status | string | 是 | 用户状态枚举值 |
|
||
| reason | string | 否 | 修改原因 |
|
||
|
||
```json
|
||
{
|
||
"status": "locked",
|
||
"reason": "用户违反社区规定"
|
||
}
|
||
```
|
||
|
||
**用户状态枚举值:**
|
||
- `active` - 正常状态,可以正常使用
|
||
- `inactive` - 未激活,需要邮箱验证
|
||
- `locked` - 已锁定,临时禁用
|
||
- `banned` - 已禁用,管理员操作
|
||
- `deleted` - 已删除,软删除状态
|
||
- `pending` - 待审核,需要管理员审核
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"user": {
|
||
"id": "1",
|
||
"username": "testuser",
|
||
"nickname": "测试用户",
|
||
"status": "locked",
|
||
"status_description": "已锁定",
|
||
"updated_at": "2025-12-24T10:00:00.000Z"
|
||
},
|
||
"reason": "用户违反社区规定"
|
||
},
|
||
"message": "用户状态修改成功"
|
||
}
|
||
```
|
||
|
||
#### 2. 批量修改用户状态
|
||
|
||
**接口地址**: `POST /admin/users/batch-status`
|
||
|
||
**功能描述**: 管理员批量修改多个用户的账户状态
|
||
|
||
#### 请求参数
|
||
|
||
```json
|
||
{
|
||
"user_ids": ["1", "2", "3"],
|
||
"status": "locked",
|
||
"reason": "批量处理违规用户"
|
||
}
|
||
```
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| user_ids | array | 是 | 用户ID列表(1-100个) |
|
||
| status | string | 是 | 用户状态枚举值 |
|
||
| reason | string | 否 | 批量修改原因 |
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"result": {
|
||
"success_users": [
|
||
{
|
||
"id": "1",
|
||
"username": "user1",
|
||
"nickname": "用户1",
|
||
"status": "locked",
|
||
"status_description": "已锁定",
|
||
"updated_at": "2025-12-24T10:00:00.000Z"
|
||
}
|
||
],
|
||
"failed_users": [
|
||
{
|
||
"user_id": "999",
|
||
"error": "用户不存在"
|
||
}
|
||
],
|
||
"success_count": 1,
|
||
"failed_count": 1,
|
||
"total_count": 2
|
||
},
|
||
"reason": "批量处理违规用户"
|
||
},
|
||
"message": "批量用户状态修改完成,成功:1,失败:1"
|
||
}
|
||
```
|
||
|
||
#### 3. 获取用户状态统计
|
||
|
||
**接口地址**: `GET /admin/users/status-stats`
|
||
|
||
**功能描述**: 获取各种用户状态的数量统计信息
|
||
|
||
#### 请求参数
|
||
|
||
无
|
||
|
||
#### 响应示例
|
||
|
||
**成功响应** (200):
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"stats": {
|
||
"active": 1250,
|
||
"inactive": 45,
|
||
"locked": 12,
|
||
"banned": 8,
|
||
"deleted": 3,
|
||
"pending": 15,
|
||
"total": 1333
|
||
},
|
||
"timestamp": "2025-12-24T10:00:00.000Z"
|
||
},
|
||
"message": "用户状态统计获取成功"
|
||
}
|
||
|
||
## 测试指南和边界条件
|
||
|
||
### 🧪 **前端测试建议**
|
||
|
||
为了确保前端应用的稳定性,建议对以下场景进行全面测试:
|
||
|
||
#### **1. 用户认证测试**
|
||
|
||
##### **注册功能测试**
|
||
```javascript
|
||
// 正常注册流程
|
||
const testNormalRegister = async () => {
|
||
// 1. 发送邮箱验证码
|
||
const codeResponse = await sendEmailVerification('test@example.com');
|
||
|
||
// 2. 使用验证码注册
|
||
const registerResponse = await register({
|
||
username: 'testuser123',
|
||
password: 'Test123456',
|
||
nickname: '测试用户',
|
||
email: 'test@example.com',
|
||
email_verification_code: codeResponse.data.verification_code
|
||
});
|
||
|
||
expect(registerResponse.success).toBe(true);
|
||
expect(registerResponse.data.user.username).toBe('testuser123');
|
||
expect(registerResponse.data.access_token).toBeDefined();
|
||
};
|
||
|
||
// 边界条件测试
|
||
const testRegisterEdgeCases = async () => {
|
||
// 密码强度测试
|
||
await expectError(register({
|
||
username: 'test',
|
||
password: '123', // 太短
|
||
nickname: '测试'
|
||
}), 'REGISTER_FAILED');
|
||
|
||
// 用户名重复测试
|
||
await expectError(register({
|
||
username: 'existinguser', // 已存在
|
||
password: 'Test123456',
|
||
nickname: '测试'
|
||
}), 'REGISTER_FAILED');
|
||
|
||
// 邮箱验证码错误测试
|
||
await expectError(register({
|
||
username: 'newuser',
|
||
password: 'Test123456',
|
||
nickname: '测试',
|
||
email: 'test@example.com',
|
||
email_verification_code: '000000' // 错误验证码
|
||
}), 'REGISTER_FAILED');
|
||
};
|
||
```
|
||
|
||
##### **登录功能测试**
|
||
```javascript
|
||
// 多种登录方式测试
|
||
const testLoginMethods = async () => {
|
||
// 用户名登录
|
||
await testLogin('testuser', 'password123');
|
||
|
||
// 邮箱登录
|
||
await testLogin('test@example.com', 'password123');
|
||
|
||
// 手机号登录(如果支持)
|
||
await testLogin('+8613800138000', 'password123');
|
||
};
|
||
|
||
// 登录失败场景测试
|
||
const testLoginFailures = async () => {
|
||
// 用户不存在
|
||
await expectError(login('nonexistent', 'password'), 'LOGIN_FAILED');
|
||
|
||
// 密码错误
|
||
await expectError(login('testuser', 'wrongpassword'), 'LOGIN_FAILED');
|
||
|
||
// 账户被锁定
|
||
await expectError(login('lockeduser', 'password'), 'LOGIN_FAILED');
|
||
};
|
||
```
|
||
|
||
#### **2. 验证码功能测试**
|
||
|
||
##### **验证码生成和验证**
|
||
```javascript
|
||
// 验证码频率限制测试
|
||
const testVerificationRateLimit = async () => {
|
||
const email = 'test@example.com';
|
||
|
||
// 第一次发送 - 应该成功
|
||
const response1 = await sendEmailVerification(email);
|
||
expect(response1.success).toBe(true);
|
||
|
||
// 立即再次发送 - 应该被限制
|
||
await expectError(
|
||
sendEmailVerification(email),
|
||
'TOO_MANY_REQUESTS',
|
||
429
|
||
);
|
||
|
||
// 等待冷却时间后再次发送
|
||
await sleep(60000); // 等待1分钟
|
||
const response2 = await sendEmailVerification(email);
|
||
expect(response2.success).toBe(true);
|
||
};
|
||
|
||
// 验证码尝试次数限制测试
|
||
const testVerificationAttempts = async () => {
|
||
const email = 'test@example.com';
|
||
const response = await sendEmailVerification(email);
|
||
const correctCode = response.data.verification_code;
|
||
|
||
// 错误尝试3次
|
||
for (let i = 0; i < 3; i++) {
|
||
await expectError(
|
||
verifyEmail(email, '000000'),
|
||
'VERIFICATION_FAILED'
|
||
);
|
||
}
|
||
|
||
// 第4次尝试,即使验证码正确也应该失败
|
||
await expectError(
|
||
verifyEmail(email, correctCode),
|
||
'VERIFICATION_FAILED'
|
||
);
|
||
};
|
||
```
|
||
|
||
#### **3. 管理员功能测试**
|
||
|
||
##### **权限验证测试**
|
||
```javascript
|
||
// 管理员登录测试
|
||
const testAdminLogin = async () => {
|
||
// 正确的管理员凭据
|
||
const response = await adminLogin('admin', 'Admin123456');
|
||
expect(response.success).toBe(true);
|
||
expect(response.data.admin.role).toBe(9);
|
||
|
||
// 普通用户尝试管理员登录
|
||
await expectError(
|
||
adminLogin('normaluser', 'password'),
|
||
'ADMIN_LOGIN_FAILED',
|
||
403
|
||
);
|
||
};
|
||
|
||
// 管理员操作权限测试
|
||
const testAdminOperations = async () => {
|
||
const adminToken = await getAdminToken();
|
||
|
||
// 有效token的操作
|
||
const users = await getUserList(adminToken);
|
||
expect(users.success).toBe(true);
|
||
|
||
// 无效token的操作
|
||
await expectError(
|
||
getUserList('invalid_token'),
|
||
'UNAUTHORIZED',
|
||
401
|
||
);
|
||
|
||
// 普通用户token的操作
|
||
const userToken = await getUserToken();
|
||
await expectError(
|
||
getUserList(userToken),
|
||
'FORBIDDEN',
|
||
403
|
||
);
|
||
};
|
||
```
|
||
|
||
#### **4. 用户状态管理测试**
|
||
|
||
##### **状态变更测试**
|
||
```javascript
|
||
// 用户状态修改测试
|
||
const testUserStatusUpdate = async () => {
|
||
const adminToken = await getAdminToken();
|
||
const userId = '1';
|
||
|
||
// 锁定用户
|
||
const lockResponse = await updateUserStatus(adminToken, userId, {
|
||
status: 'locked',
|
||
reason: '违反社区规定'
|
||
});
|
||
expect(lockResponse.success).toBe(true);
|
||
expect(lockResponse.data.user.status).toBe('locked');
|
||
|
||
// 被锁定用户尝试登录
|
||
await expectError(
|
||
login('lockeduser', 'password'),
|
||
'LOGIN_FAILED',
|
||
403
|
||
);
|
||
|
||
// 恢复用户状态
|
||
await updateUserStatus(adminToken, userId, {
|
||
status: 'active',
|
||
reason: '恢复正常'
|
||
});
|
||
};
|
||
|
||
// 批量状态修改测试
|
||
const testBatchStatusUpdate = async () => {
|
||
const adminToken = await getAdminToken();
|
||
|
||
const response = await batchUpdateUserStatus(adminToken, {
|
||
user_ids: ['1', '2', '999'], // 包含不存在的用户ID
|
||
status: 'locked',
|
||
reason: '批量处理'
|
||
});
|
||
|
||
expect(response.success).toBe(true);
|
||
expect(response.data.result.success_count).toBe(2);
|
||
expect(response.data.result.failed_count).toBe(1);
|
||
expect(response.data.result.failed_users[0].user_id).toBe('999');
|
||
};
|
||
```
|
||
|
||
#### **5. 安全功能测试**
|
||
|
||
##### **频率限制测试**
|
||
```javascript
|
||
// 登录频率限制测试
|
||
const testLoginRateLimit = async () => {
|
||
// 快速连续登录尝试
|
||
for (let i = 0; i < 3; i++) {
|
||
try {
|
||
await login('testuser', 'wrongpassword');
|
||
} catch (error) {
|
||
if (error.status === 429) {
|
||
expect(error.message).toContain('Too Many Requests');
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// 维护模式测试
|
||
const testMaintenanceMode = async () => {
|
||
// 模拟维护模式开启
|
||
// 所有请求都应该返回503
|
||
await expectError(
|
||
getAppStatus(),
|
||
'SERVICE_UNAVAILABLE',
|
||
503
|
||
);
|
||
};
|
||
```
|
||
|
||
#### **6. 错误处理测试**
|
||
|
||
##### **网络错误处理**
|
||
```javascript
|
||
// 超时处理测试
|
||
const testTimeout = async () => {
|
||
// 模拟长时间操作
|
||
await expectError(
|
||
slowOperation(),
|
||
'REQUEST_TIMEOUT',
|
||
408
|
||
);
|
||
};
|
||
|
||
// 内容类型验证测试
|
||
const testContentType = async () => {
|
||
// 错误的Content-Type
|
||
await expectError(
|
||
fetch('/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'text/plain' },
|
||
body: 'invalid data'
|
||
}),
|
||
'UNSUPPORTED_MEDIA_TYPE',
|
||
415
|
||
);
|
||
};
|
||
```
|
||
|
||
### 📋 **测试检查清单**
|
||
|
||
#### **功能测试**
|
||
- [ ] 用户注册(正常流程)
|
||
- [ ] 用户注册(邮箱验证流程)
|
||
- [ ] 用户登录(用户名/邮箱/手机号)
|
||
- [ ] GitHub OAuth登录
|
||
- [ ] 密码重置流程
|
||
- [ ] 密码修改功能
|
||
- [ ] 邮箱验证码发送和验证
|
||
- [ ] 管理员登录
|
||
- [ ] 用户列表查询
|
||
- [ ] 用户详情查询
|
||
- [ ] 用户密码重置(管理员)
|
||
- [ ] 用户状态管理
|
||
- [ ] 批量用户状态修改
|
||
- [ ] 用户状态统计
|
||
- [ ] 运行日志查询
|
||
- [ ] 日志文件下载
|
||
|
||
#### **边界条件测试**
|
||
- [ ] 密码强度验证(太短、太简单)
|
||
- [ ] 用户名格式验证(特殊字符、长度)
|
||
- [ ] 邮箱格式验证
|
||
- [ ] 验证码格式验证(非6位数字)
|
||
- [ ] 用户名重复检查
|
||
- [ ] 邮箱重复检查
|
||
- [ ] 不存在用户的操作
|
||
- [ ] 无效验证码验证
|
||
- [ ] 过期验证码验证
|
||
- [ ] 验证码尝试次数限制
|
||
|
||
#### **安全测试**
|
||
- [ ] 频率限制(登录、发送验证码)
|
||
- [ ] 权限验证(管理员接口)
|
||
- [ ] Token有效性验证
|
||
- [ ] 用户状态检查(锁定、禁用用户登录)
|
||
- [ ] 维护模式功能
|
||
- [ ] 内容类型验证
|
||
- [ ] 请求超时处理
|
||
|
||
#### **错误处理测试**
|
||
- [ ] 网络连接错误
|
||
- [ ] 服务器内部错误(500)
|
||
- [ ] 请求超时(408)
|
||
- [ ] 频率限制(429)
|
||
- [ ] 权限不足(403)
|
||
- [ ] 资源不存在(404)
|
||
- [ ] 参数验证错误(400)
|
||
- [ ] 维护模式(503)
|
||
|
||
### 🔧 **测试工具推荐**
|
||
|
||
#### **API测试工具**
|
||
- **Postman**: 手动API测试和文档
|
||
- **Insomnia**: 轻量级API客户端
|
||
- **curl**: 命令行测试
|
||
- **HTTPie**: 用户友好的命令行工具
|
||
|
||
#### **自动化测试框架**
|
||
- **Jest**: JavaScript测试框架
|
||
- **Cypress**: 端到端测试
|
||
- **Playwright**: 现代Web测试
|
||
- **Supertest**: Node.js HTTP测试
|
||
|
||
#### **测试脚本示例**
|
||
项目提供了现成的测试脚本:
|
||
- `test-api.ps1` - Windows PowerShell测试脚本
|
||
- `test-api.sh` - Linux/macOS Bash测试脚本
|
||
|
||
运行测试脚本:
|
||
```bash
|
||
# Windows
|
||
.\test-api.ps1
|
||
|
||
# Linux/macOS
|
||
./test-api.sh
|
||
|
||
# 自定义参数
|
||
.\test-api.ps1 -BaseUrl "http://localhost:3000" -TestEmail "custom@example.com"
|
||
```
|
||
|
||
### 📊 **测试数据管理**
|
||
|
||
#### **测试环境配置**
|
||
- **内存模式**: 数据重启后清空,适合快速测试
|
||
- **数据库模式**: 数据持久化,适合完整功能测试
|
||
- **测试模式**: 邮件不真实发送,验证码在响应中返回
|
||
|
||
#### **测试数据清理**
|
||
```javascript
|
||
// 清理测试数据
|
||
const cleanupTestData = async () => {
|
||
// 删除测试用户
|
||
await deleteTestUsers();
|
||
|
||
// 清理Redis验证码
|
||
await clearVerificationCodes();
|
||
|
||
// 重置计数器
|
||
await resetRateLimitCounters();
|
||
};
|
||
```
|
||
|
||
### ⚠️ **测试注意事项**
|
||
|
||
1. **频率限制**: 测试时注意API频率限制,避免被限制
|
||
2. **测试隔离**: 每个测试用例使用独立的测试数据
|
||
3. **异步操作**: 注意验证码生成和验证的时序
|
||
4. **错误恢复**: 测试失败后要清理测试数据
|
||
5. **环境差异**: 开发、测试、生产环境的配置差异
|
||
6. **数据一致性**: 并发测试时注意数据竞争条件
|
||
|
||
### 🚀 **性能测试建议**
|
||
|
||
#### **负载测试场景**
|
||
- 并发用户注册
|
||
- 高频验证码发送
|
||
- 大量用户同时登录
|
||
- 管理员批量操作
|
||
- 日志文件下载
|
||
|
||
#### **性能指标**
|
||
- 响应时间 < 2秒(正常操作)
|
||
- 吞吐量 > 100 req/s
|
||
- 错误率 < 1%
|
||
- 内存使用稳定
|
||
- CPU使用率 < 80%
|
||
|
||
### **通用错误代码**
|
||
|
||
| 错误代码 | HTTP状态码 | 说明 | 触发条件 |
|
||
|----------|------------|------|----------|
|
||
| LOGIN_FAILED | 401 | 登录失败 | 用户名不存在、密码错误、账户被锁定 |
|
||
| REGISTER_FAILED | 400/409 | 注册失败 | 用户名已存在、密码强度不足、验证码错误 |
|
||
| GITHUB_OAUTH_FAILED | 401 | GitHub OAuth失败 | GitHub认证信息无效 |
|
||
| SEND_CODE_FAILED | 400 | 发送验证码失败 | 邮箱格式错误、发送服务异常 |
|
||
| RESET_PASSWORD_FAILED | 400 | 重置密码失败 | 验证码无效、密码强度不足 |
|
||
| CHANGE_PASSWORD_FAILED | 400 | 修改密码失败 | 旧密码错误、新密码强度不足 |
|
||
| TEST_MODE_ONLY | 206 | 测试模式 | 邮件服务未配置,验证码未真实发送 |
|
||
|
||
### **管理员相关错误代码**
|
||
|
||
| 错误代码 | HTTP状态码 | 说明 | 触发条件 |
|
||
|----------|------------|------|----------|
|
||
| ADMIN_LOGIN_FAILED | 401/403 | 管理员登录失败 | 非管理员用户、凭据错误 |
|
||
| ADMIN_USERS_FAILED | 500 | 获取用户列表失败 | 数据库查询异常 |
|
||
| ADMIN_OPERATION_FAILED | 400/500 | 管理员操作失败 | 参数错误、系统异常 |
|
||
|
||
### **用户状态相关错误代码**
|
||
|
||
| 错误代码 | HTTP状态码 | 说明 | 触发条件 |
|
||
|----------|------------|------|----------|
|
||
| USER_STATUS_UPDATE_FAILED | 400/404 | 用户状态修改失败 | 用户不存在、状态值无效 |
|
||
| BATCH_USER_STATUS_UPDATE_FAILED | 400 | 批量用户状态修改失败 | 用户ID列表为空、状态值无效 |
|
||
| USER_STATUS_STATS_FAILED | 500 | 用户状态统计失败 | 数据库查询异常 |
|
||
|
||
### **安全相关错误代码**
|
||
|
||
| 错误代码 | HTTP状态码 | 说明 | 触发条件 |
|
||
|----------|------------|------|----------|
|
||
| SERVICE_UNAVAILABLE | 503 | 系统维护中 | 维护模式开启 |
|
||
| TOO_MANY_REQUESTS | 429 | 请求过于频繁 | 触发频率限制 |
|
||
| REQUEST_TIMEOUT | 408 | 请求超时 | 操作执行时间过长 |
|
||
| UNSUPPORTED_MEDIA_TYPE | 415 | 不支持的媒体类型 | Content-Type不正确 |
|
||
| UNAUTHORIZED | 401 | 未授权 | Token无效或过期 |
|
||
| FORBIDDEN | 403 | 权限不足 | 非管理员访问管理员接口 |
|
||
|
||
### **验证码相关错误代码**
|
||
|
||
| 错误代码 | HTTP状态码 | 说明 | 触发条件 |
|
||
|----------|------------|------|----------|
|
||
| VERIFICATION_CODE_EXPIRED | 400 | 验证码已过期 | 验证码超过有效期(5分钟) |
|
||
| VERIFICATION_CODE_INVALID | 400 | 验证码无效 | 验证码格式错误或不存在 |
|
||
| VERIFICATION_CODE_LOGIN_FAILED | 401 | 验证码登录失败 | 验证码错误、已过期或用户邮箱未验证 |
|
||
| SEND_LOGIN_CODE_FAILED | 400/404 | 发送登录验证码失败 | 用户不存在或发送服务异常 |
|
||
| VERIFICATION_CODE_ATTEMPTS_EXCEEDED | 400 | 验证码尝试次数过多 | 错误尝试超过3次 |
|
||
| VERIFICATION_CODE_RATE_LIMITED | 429 | 验证码发送频率限制 | 1分钟内重复发送 |
|
||
| VERIFICATION_CODE_HOURLY_LIMIT | 429 | 验证码每小时限制 | 1小时内发送超过5次 |
|
||
|
||
### **详细错误响应格式**
|
||
|
||
#### **标准错误响应**
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "具体错误描述",
|
||
"error_code": "ERROR_CODE",
|
||
"timestamp": "2025-12-24T10:00:00.000Z"
|
||
}
|
||
```
|
||
|
||
#### **验证错误响应**
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "参数验证失败",
|
||
"error_code": "VALIDATION_FAILED",
|
||
"errors": [
|
||
{
|
||
"field": "password",
|
||
"message": "密码长度至少8位"
|
||
},
|
||
{
|
||
"field": "email",
|
||
"message": "邮箱格式不正确"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### **频率限制错误响应**
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "请求过于频繁,请稍后再试",
|
||
"error_code": "TOO_MANY_REQUESTS",
|
||
"retry_after": 60,
|
||
"limit_info": {
|
||
"limit": 5,
|
||
"remaining": 0,
|
||
"reset_time": "2025-12-24T10:01:00.000Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### **维护模式错误响应**
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "系统正在维护中,请稍后再试",
|
||
"error_code": "SERVICE_UNAVAILABLE",
|
||
"maintenance_info": {
|
||
"start_time": "2025-12-24T10:00:00.000Z",
|
||
"estimated_end_time": "2025-12-24T12:00:00.000Z",
|
||
"retry_after": 1800,
|
||
"reason": "系统升级维护"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 数据验证规则
|
||
|
||
### 用户名规则
|
||
- 长度:1-50字符
|
||
- 格式:只能包含字母、数字和下划线
|
||
- 正则表达式:`^[a-zA-Z0-9_]+$`
|
||
|
||
### 密码规则
|
||
- 长度:8-128字符
|
||
- 格式:必须包含字母和数字
|
||
- 正则表达式:`^(?=.*[a-zA-Z])(?=.*\d)`
|
||
|
||
### 验证码规则
|
||
- 长度:6位数字
|
||
- 正则表达式:`^\d{6}$`
|
||
- 有效期:通常为5-15分钟
|
||
|
||
### 邮箱规则
|
||
- 格式:符合标准邮箱格式
|
||
- 验证:支持邮箱验证码验证
|
||
|
||
### 管理员权限
|
||
- 角色:role=9 为管理员
|
||
- 认证:需要 JWT Token
|
||
- 权限:可管理所有用户数据
|
||
|
||
## 使用示例
|
||
|
||
### JavaScript/TypeScript 示例
|
||
|
||
```typescript
|
||
// 获取应用状态
|
||
const statusResponse = await fetch('http://localhost:3000/');
|
||
const statusData = await statusResponse.json();
|
||
console.log('服务状态:', statusData.status);
|
||
|
||
// 用户登录
|
||
const loginResponse = await fetch('http://localhost:3000/auth/login', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
identifier: 'testuser',
|
||
password: 'password123'
|
||
})
|
||
});
|
||
|
||
const loginData = await loginResponse.json();
|
||
if (loginData.success) {
|
||
const token = loginData.data.access_token;
|
||
// 保存token用于后续请求
|
||
localStorage.setItem('token', token);
|
||
}
|
||
|
||
// 用户注册(带邮箱验证)
|
||
// 1. 先发送邮箱验证码
|
||
const sendCodeResponse = await fetch('http://localhost:3000/auth/send-email-verification', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
email: 'newuser@example.com'
|
||
})
|
||
});
|
||
|
||
// 2. 用户输入验证码后进行注册
|
||
const registerResponse = await fetch('http://localhost:3000/auth/register', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
username: 'newuser',
|
||
password: 'password123',
|
||
nickname: '新用户',
|
||
email: 'newuser@example.com',
|
||
email_verification_code: '123456'
|
||
})
|
||
});
|
||
|
||
// 管理员登录
|
||
const adminLoginResponse = await fetch('http://localhost:3000/admin/auth/login', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
identifier: 'admin',
|
||
password: 'Admin123456'
|
||
})
|
||
});
|
||
|
||
const adminData = await adminLoginResponse.json();
|
||
if (adminData.success) {
|
||
const adminToken = adminData.data.access_token;
|
||
|
||
// 获取用户列表
|
||
const usersResponse = await fetch('http://localhost:3000/admin/users?limit=10&offset=0', {
|
||
headers: {
|
||
'Authorization': `Bearer ${adminToken}`
|
||
}
|
||
});
|
||
|
||
const usersData = await usersResponse.json();
|
||
console.log('用户列表:', usersData.data.users);
|
||
}
|
||
```
|
||
|
||
### cURL 示例
|
||
|
||
```bash
|
||
# 获取应用状态
|
||
curl -X GET http://localhost:3000/
|
||
|
||
# 用户登录
|
||
curl -X POST http://localhost:3000/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"identifier": "testuser",
|
||
"password": "password123"
|
||
}'
|
||
|
||
# 发送登录验证码
|
||
curl -X POST http://localhost:3000/auth/send-login-verification-code \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"identifier": "test@example.com"
|
||
}'
|
||
|
||
# 验证码登录
|
||
curl -X POST http://localhost:3000/auth/verification-code-login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"identifier": "test@example.com",
|
||
"verification_code": "123456"
|
||
}'
|
||
|
||
# 发送邮箱验证码
|
||
curl -X POST http://localhost:3000/auth/send-email-verification \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"email": "newuser@example.com"
|
||
}'
|
||
|
||
# 用户注册
|
||
curl -X POST http://localhost:3000/auth/register \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"username": "newuser",
|
||
"password": "password123",
|
||
"nickname": "新用户",
|
||
"email": "newuser@example.com",
|
||
"email_verification_code": "123456"
|
||
}'
|
||
|
||
# 管理员登录
|
||
curl -X POST http://localhost:3000/admin/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"identifier": "admin",
|
||
"password": "Admin123456"
|
||
}'
|
||
|
||
# 获取用户列表(需要管理员Token)
|
||
curl -X GET "http://localhost:3000/admin/users?limit=10&offset=0" \
|
||
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
|
||
|
||
# 重置用户密码
|
||
curl -X POST http://localhost:3000/admin/users/1/reset-password \
|
||
-H "Content-Type: application/json" \
|
||
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
||
-d '{
|
||
"new_password": "NewPass1234"
|
||
}'
|
||
|
||
# 获取运行日志
|
||
curl -X GET "http://localhost:3000/admin/logs/runtime?lines=100" \
|
||
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
|
||
|
||
# 下载日志压缩包
|
||
curl -X GET http://localhost:3000/admin/logs/archive \
|
||
-H "Authorization: Bearer YOUR_ADMIN_TOKEN" \
|
||
-o logs.tar.gz
|
||
```
|
||
|
||
## 安全特性
|
||
|
||
### 1. 频率限制 (Rate Limiting)
|
||
|
||
系统实现了基于IP地址的频率限制,防止恶意攻击和滥用:
|
||
|
||
#### 限制策略
|
||
|
||
| 接口类型 | 限制规则 | 时间窗口 | 说明 |
|
||
|----------|----------|----------|------|
|
||
| 登录接口 | 5次/分钟 | 60秒 | 防止暴力破解 |
|
||
| 注册接口 | 10次/5分钟 | 300秒 | 防止批量注册(开发环境已放宽) |
|
||
| 发送验证码 | 1次/分钟 | 60秒 | 防止验证码滥发 |
|
||
| 密码重置 | 3次/小时 | 3600秒 | 限制密码重置频率 |
|
||
| 管理员操作 | 10次/分钟 | 60秒 | 限制管理员操作频率 |
|
||
| 一般接口 | 30次/分钟 | 60秒 | 通用API限制 | 100次/分钟 | 60秒 | 防止接口滥用 |
|
||
|
||
#### 响应示例
|
||
|
||
当触发频率限制时,返回 **429 Too Many Requests**:
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "注册请求过于频繁,请5分钟后再试",
|
||
"error_code": "TOO_MANY_REQUESTS",
|
||
"throttle_info": {
|
||
"limit": 10,
|
||
"window_seconds": 300,
|
||
"current_requests": 10,
|
||
"reset_time": "2025-12-24T11:26:41.136Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
**重要说明**:
|
||
- 频率限制基于IP地址
|
||
- 超过限制后需要等待到重置时间才能再次请求
|
||
- 开发环境下注册接口限制已放宽至10次/5分钟
|
||
|
||
### 2. 维护模式 (Maintenance Mode)
|
||
|
||
系统支持维护模式,在系统升级或维护期间暂停服务:
|
||
|
||
#### 启用方式
|
||
|
||
设置环境变量:
|
||
```bash
|
||
MAINTENANCE_MODE=true
|
||
MAINTENANCE_START_TIME=2025-12-24T10:00:00.000Z
|
||
MAINTENANCE_END_TIME=2025-12-24T12:00:00.000Z
|
||
MAINTENANCE_REASON=系统升级维护
|
||
MAINTENANCE_RETRY_AFTER=1800
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
维护模式下所有请求返回 **503 Service Unavailable**:
|
||
|
||
```json
|
||
{
|
||
"success": false,
|
||
"message": "系统正在维护中,请稍后再试",
|
||
"error_code": "SERVICE_UNAVAILABLE",
|
||
"maintenance_info": {
|
||
"start_time": "2025-12-24T10:00:00.000Z",
|
||
"estimated_end_time": "2025-12-24T12:00:00.000Z",
|
||
"retry_after": 1800,
|
||
"reason": "系统升级维护"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 内容类型验证 (Content Type Validation)
|
||
|
||
系统验证POST/PUT请求的Content-Type头:
|
||
|
||
#### 支持的内容类型
|
||
|
||
- `application/json` - JSON数据
|
||
- `application/x-www-form-urlencoded` - 表单数据
|
||
- `multipart/form-data` - 文件上传
|
||
|
||
#### 响应示例
|
||
|
||
不支持的内容类型返回 **415 Unsupported Media Type**:
|
||
|
||
```json
|
||
{
|
||
"statusCode": 415,
|
||
"message": "不支持的媒体类型",
|
||
"error": "Unsupported Media Type"
|
||
}
|
||
```
|
||
|
||
### 4. 请求超时控制 (Request Timeout)
|
||
|
||
系统为不同类型的操作设置了超时限制:
|
||
|
||
#### 超时配置
|
||
|
||
| 操作类型 | 超时时间 | 说明 |
|
||
|----------|----------|------|
|
||
| 普通操作 | 30秒 | 一般API请求 |
|
||
| 数据库查询 | 60秒 | 复杂查询操作 |
|
||
| 慢操作 | 120秒 | 批量处理等耗时操作 |
|
||
|
||
#### 响应示例
|
||
|
||
请求超时返回 **408 Request Timeout**:
|
||
|
||
```json
|
||
{
|
||
"statusCode": 408,
|
||
"message": "请求超时",
|
||
"error": "Request Timeout"
|
||
}
|
||
```
|
||
|
||
### 5. 用户状态管理 (User Status Management)
|
||
|
||
系统支持细粒度的用户状态控制:
|
||
|
||
#### 用户状态枚举
|
||
|
||
| 状态值 | 状态名称 | 说明 |
|
||
|--------|----------|------|
|
||
| active | 正常 | 用户可以正常使用所有功能 |
|
||
| inactive | 未激活 | 新注册用户,需要邮箱验证 |
|
||
| locked | 锁定 | 临时锁定,可以解锁 |
|
||
| banned | 禁用 | 永久禁用,需要管理员处理 |
|
||
| deleted | 删除 | 软删除状态,数据保留 |
|
||
| pending | 待审核 | 需要管理员审核激活 |
|
||
|
||
#### 状态检查
|
||
|
||
登录时系统会检查用户状态:
|
||
|
||
- `active`: 正常登录
|
||
- `inactive`: 提示需要邮箱验证
|
||
- `locked`: 返回账户锁定错误
|
||
- `banned`: 返回账户禁用错误
|
||
- `deleted`: 返回账户不存在错误
|
||
- `pending`: 返回账户待审核错误
|
||
|
||
### 6. 安全最佳实践
|
||
|
||
#### JWT Token 安全
|
||
|
||
- Token 有效期:8小时
|
||
- 使用 HS256 算法签名
|
||
- 包含用户ID、角色等关键信息
|
||
- 建议在客户端安全存储
|
||
|
||
#### 密码安全
|
||
|
||
- 使用 bcrypt 加密存储
|
||
- 支持密码强度验证
|
||
- 不在日志中记录明文密码
|
||
- 支持密码重置功能
|
||
|
||
#### API 安全
|
||
|
||
- 所有管理员接口需要身份验证
|
||
- 支持跨域资源共享 (CORS)
|
||
- 实现请求日志记录
|
||
- 敏感信息自动脱敏
|
||
|
||
## 注意事项
|
||
|
||
1. **安全性**: 实际应用中应使用HTTPS协议
|
||
2. **令牌**: 示例中的access_token是JWT格式,需要妥善保存
|
||
3. **验证码**:
|
||
- 实际应用中不应在响应中返回验证码
|
||
- 测试模式下会在控制台显示验证码,或通过调试接口获取
|
||
- 验证码有效期通常为5分钟
|
||
- 验证码登录要求邮箱已验证(email_verified=true)
|
||
- 调试接口:`POST /auth/debug-verification-code` 可获取验证码详情
|
||
4. **用户ID**: 修改密码接口中的user_id应从JWT令牌中获取,而不是从请求体中传递
|
||
5. **错误处理**: 建议在客户端实现适当的错误处理和用户提示
|
||
6. **限流**: 建议对登录、注册等接口实施限流策略
|
||
7. **管理员权限**:
|
||
- 管理员接口需要 role=9 的用户权限
|
||
- 需要在请求头中携带有效的JWT Token
|
||
- Token格式:`Authorization: Bearer <token>`
|
||
8. **存储模式**:
|
||
- 数据库模式:数据持久化存储在MySQL
|
||
- 内存模式:数据存储在内存中,重启后丢失
|
||
9. **邮箱验证**:
|
||
- 注册时如果提供邮箱,需要先获取验证码
|
||
- 支持重新发送验证码功能
|
||
- 调试接口仅用于开发环境
|
||
10. **验证码登录**:
|
||
- 验证码登录需要用户邮箱已验证
|
||
- 支持邮箱和手机号两种方式
|
||
- 验证码类型为 `login_verification`
|
||
- 与注册验证码是不同的验证码类型
|
||
|
||
## 常见测试场景
|
||
|
||
### 🔍 **前端开发者必测场景**
|
||
|
||
#### **1. 用户注册完整流程**
|
||
```javascript
|
||
// 场景:新用户完整注册流程
|
||
const testCompleteRegistration = async () => {
|
||
const email = 'newuser@example.com';
|
||
|
||
// Step 1: 发送邮箱验证码
|
||
const codeResponse = await fetch('/auth/send-email-verification', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email })
|
||
});
|
||
|
||
expect(codeResponse.status).toBe(206); // 测试模式
|
||
const codeData = await codeResponse.json();
|
||
expect(codeData.success).toBe(false);
|
||
expect(codeData.error_code).toBe('TEST_MODE_ONLY');
|
||
|
||
// Step 2: 使用验证码注册
|
||
const registerResponse = await fetch('/auth/register', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
username: 'newuser123',
|
||
password: 'SecurePass123',
|
||
nickname: '新用户',
|
||
email: email,
|
||
email_verification_code: codeData.data.verification_code
|
||
})
|
||
});
|
||
|
||
expect(registerResponse.status).toBe(201);
|
||
const registerData = await registerResponse.json();
|
||
expect(registerData.success).toBe(true);
|
||
expect(registerData.data.access_token).toBeDefined();
|
||
};
|
||
```
|
||
|
||
#### **2. 验证码登录完整流程**
|
||
```javascript
|
||
// 场景:验证码登录完整流程
|
||
const testVerificationCodeLogin = async () => {
|
||
const email = 'test@example.com';
|
||
|
||
// Step 1: 发送登录验证码
|
||
const codeResponse = await fetch('/auth/send-login-verification-code', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ identifier: email })
|
||
});
|
||
|
||
expect(codeResponse.status).toBe(206); // 测试模式
|
||
const codeData = await codeResponse.json();
|
||
expect(codeData.success).toBe(false);
|
||
expect(codeData.error_code).toBe('TEST_MODE_ONLY');
|
||
|
||
// Step 2: 使用验证码登录
|
||
const loginResponse = await fetch('/auth/verification-code-login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
identifier: email,
|
||
verification_code: codeData.data.verification_code
|
||
})
|
||
});
|
||
|
||
expect(loginResponse.status).toBe(200);
|
||
const loginData = await loginResponse.json();
|
||
expect(loginData.success).toBe(true);
|
||
expect(loginData.data.access_token).toBeDefined();
|
||
};
|
||
```
|
||
|
||
#### **3. 登录失败处理**
|
||
```javascript
|
||
// 场景:各种登录失败情况
|
||
const testLoginFailures = async () => {
|
||
// 用户不存在
|
||
const response1 = await fetch('/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
identifier: 'nonexistent',
|
||
password: 'password123'
|
||
})
|
||
});
|
||
|
||
expect(response1.status).toBe(200); // 业务错误返回200
|
||
const data1 = await response1.json();
|
||
expect(data1.success).toBe(false);
|
||
expect(data1.error_code).toBe('LOGIN_FAILED');
|
||
|
||
// 密码错误
|
||
const response2 = await fetch('/auth/login', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
identifier: 'existinguser',
|
||
password: 'wrongpassword'
|
||
})
|
||
});
|
||
|
||
expect(response2.status).toBe(200);
|
||
const data2 = await response2.json();
|
||
expect(data2.success).toBe(false);
|
||
expect(data2.error_code).toBe('LOGIN_FAILED');
|
||
};
|
||
```
|
||
|
||
#### **4. 频率限制测试**
|
||
```javascript
|
||
// 场景:验证码发送频率限制
|
||
const testRateLimit = async () => {
|
||
const email = 'test@example.com';
|
||
|
||
// 第一次发送 - 成功
|
||
const response1 = await fetch('/auth/send-email-verification', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email })
|
||
});
|
||
expect(response1.status).toBe(206); // 测试模式
|
||
|
||
// 立即再次发送 - 被限制
|
||
const response2 = await fetch('/auth/send-email-verification', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email })
|
||
});
|
||
expect(response2.status).toBe(429);
|
||
|
||
const data2 = await response2.json();
|
||
expect(data2.message).toContain('请等待');
|
||
};
|
||
```
|
||
|
||
#### **5. 管理员权限测试**
|
||
```javascript
|
||
// 场景:管理员权限验证
|
||
const testAdminPermissions = async () => {
|
||
// 普通用户尝试访问管理员接口
|
||
const userToken = 'user_token_here';
|
||
|
||
const response = await fetch('/admin/users', {
|
||
headers: { 'Authorization': `Bearer ${userToken}` }
|
||
});
|
||
|
||
expect(response.status).toBe(403);
|
||
|
||
// 无效token访问
|
||
const response2 = await fetch('/admin/users', {
|
||
headers: { 'Authorization': 'Bearer invalid_token' }
|
||
});
|
||
|
||
expect(response2.status).toBe(401);
|
||
|
||
// 正确的管理员token
|
||
const adminToken = await getAdminToken();
|
||
const response3 = await fetch('/admin/users', {
|
||
headers: { 'Authorization': `Bearer ${adminToken}` }
|
||
});
|
||
|
||
expect(response3.status).toBe(200);
|
||
};
|
||
```
|
||
|
||
#### **6. 用户状态影响登录**
|
||
```javascript
|
||
// 场景:不同用户状态的登录测试
|
||
const testUserStatusLogin = async () => {
|
||
// 正常用户登录
|
||
const activeResponse = await login('activeuser', 'password');
|
||
expect(activeResponse.success).toBe(true);
|
||
|
||
// 锁定用户登录
|
||
const lockedResponse = await login('lockeduser', 'password');
|
||
expect(lockedResponse.success).toBe(false);
|
||
expect(lockedResponse.message).toContain('锁定');
|
||
|
||
// 禁用用户登录
|
||
const bannedResponse = await login('banneduser', 'password');
|
||
expect(bannedResponse.success).toBe(false);
|
||
expect(bannedResponse.message).toContain('禁用');
|
||
};
|
||
```
|
||
|
||
### 📝 **边界条件测试清单**
|
||
|
||
#### **输入验证测试**
|
||
- [ ] 空字符串输入
|
||
- [ ] 超长字符串输入(用户名>50字符)
|
||
- [ ] 特殊字符输入(SQL注入尝试)
|
||
- [ ] 无效邮箱格式
|
||
- [ ] 弱密码(少于8位、纯数字、纯字母)
|
||
- [ ] 无效验证码格式(非6位数字)
|
||
|
||
#### **状态边界测试**
|
||
- [ ] 验证码过期边界(5分钟)
|
||
- [ ] 验证码尝试次数边界(3次)
|
||
- [ ] 频率限制边界(1分钟、1小时)
|
||
- [ ] Token过期边界(8小时)
|
||
- [ ] 用户状态变更后的立即登录
|
||
|
||
#### **并发测试**
|
||
- [ ] 同时发送多个验证码请求
|
||
- [ ] 同时使用相同验证码验证
|
||
- [ ] 并发用户注册相同用户名
|
||
- [ ] 并发管理员操作同一用户
|
||
|
||
### 🚨 **错误恢复测试**
|
||
|
||
#### **网络异常处理**
|
||
```javascript
|
||
// 场景:网络中断恢复
|
||
const testNetworkRecovery = async () => {
|
||
// 模拟网络中断
|
||
mockNetworkError();
|
||
|
||
try {
|
||
await login('testuser', 'password');
|
||
fail('应该抛出网络错误');
|
||
} catch (error) {
|
||
expect(error.message).toContain('网络');
|
||
}
|
||
|
||
// 恢复网络
|
||
restoreNetwork();
|
||
|
||
// 重试应该成功
|
||
const response = await login('testuser', 'password');
|
||
expect(response.success).toBe(true);
|
||
};
|
||
```
|
||
|
||
#### **服务降级测试**
|
||
```javascript
|
||
// 场景:邮件服务不可用时的降级
|
||
const testEmailServiceDegradation = async () => {
|
||
// 邮件服务不可用时,应该返回测试模式
|
||
const response = await fetch('/auth/send-email-verification', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ email: 'test@example.com' })
|
||
});
|
||
|
||
expect(response.status).toBe(206);
|
||
const data = await response.json();
|
||
expect(data.error_code).toBe('TEST_MODE_ONLY');
|
||
expect(data.data.is_test_mode).toBe(true);
|
||
};
|
||
```
|
||
|
||
### 🔧 **自动化测试脚本**
|
||
|
||
#### **快速冒烟测试**
|
||
```bash
|
||
#!/bin/bash
|
||
# 快速验证所有关键接口
|
||
|
||
BASE_URL="http://localhost:3000"
|
||
|
||
echo "🚀 开始API冒烟测试..."
|
||
|
||
# 1. 应用状态检查
|
||
echo "1. 检查应用状态..."
|
||
curl -f "$BASE_URL/" > /dev/null || exit 1
|
||
|
||
# 2. 验证码发送
|
||
echo "2. 测试验证码发送..."
|
||
RESPONSE=$(curl -s -X POST "$BASE_URL/auth/send-email-verification" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"test@example.com"}')
|
||
|
||
CODE=$(echo "$RESPONSE" | jq -r '.data.verification_code')
|
||
if [ "$CODE" = "null" ]; then
|
||
echo "❌ 验证码发送失败"
|
||
exit 1
|
||
fi
|
||
|
||
# 3. 用户注册
|
||
echo "3. 测试用户注册..."
|
||
USERNAME="smoketest_$(date +%s)"
|
||
curl -f -X POST "$BASE_URL/auth/register" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"username\":\"$USERNAME\",\"password\":\"Test123456\",\"nickname\":\"冒烟测试\",\"email\":\"test@example.com\",\"email_verification_code\":\"$CODE\"}" > /dev/null || exit 1
|
||
|
||
# 4. 用户登录
|
||
echo "4. 测试用户登录..."
|
||
curl -f -X POST "$BASE_URL/auth/login" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"identifier\":\"$USERNAME\",\"password\":\"Test123456\"}" > /dev/null || exit 1
|
||
|
||
echo "✅ 冒烟测试通过!"
|
||
```
|
||
|
||
#### **性能基准测试**
|
||
```bash
|
||
#!/bin/bash
|
||
# 简单的性能基准测试
|
||
|
||
echo "📊 开始性能基准测试..."
|
||
|
||
# 并发登录测试
|
||
echo "测试并发登录性能..."
|
||
ab -n 100 -c 10 -T 'application/json' -p login_data.json http://localhost:3000/auth/login
|
||
|
||
# 验证码发送性能测试
|
||
echo "测试验证码发送性能..."
|
||
ab -n 50 -c 5 -T 'application/json' -p email_data.json http://localhost:3000/auth/send-email-verification
|
||
|
||
echo "📈 性能测试完成,请查看上述结果"
|
||
```
|
||
|
||
### 💡 **测试技巧和建议**
|
||
|
||
#### **1. 测试数据管理**
|
||
- 使用时间戳生成唯一的测试用户名
|
||
- 测试完成后清理测试数据
|
||
- 使用专门的测试邮箱域名
|
||
|
||
#### **2. 异步操作处理**
|
||
- 验证码生成后立即使用,避免过期
|
||
- 注意频率限制的时间窗口
|
||
- 使用适当的等待时间
|
||
|
||
#### **3. 错误场景覆盖**
|
||
- 测试所有可能的HTTP状态码
|
||
- 验证错误消息的准确性
|
||
- 测试错误恢复机制
|
||
|
||
#### **4. 安全测试**
|
||
- 尝试SQL注入和XSS攻击
|
||
- 测试权限绕过
|
||
- 验证敏感信息不泄露
|
||
|
||
这些测试场景和边界条件将帮助前端开发者进行全面的API测试,确保应用的稳定性和安全性。
|
||
|
||
- **v1.1.0** (2025-12-25):
|
||
- **新增验证码登录功能**
|
||
- 添加验证码登录接口 (POST /auth/verification-code-login)
|
||
- 添加发送登录验证码接口 (POST /auth/send-login-verification-code)
|
||
- 支持邮箱和手机号验证码登录
|
||
- 完善验证码相关错误处理和限流机制
|
||
- **文档完善**
|
||
- 更新API文档,新增验证码登录相关说明
|
||
- 修正错误码与实际响应的一致性
|
||
- 添加验证码登录测试场景和使用示例
|
||
- 更新OpenAPI规范文档
|
||
- **接口数量更新**:21个 → 23个API接口
|
||
- **用户认证接口**:11个 → 13个接口
|
||
- **v1.0.0** (2025-12-24):
|
||
- **完整的API文档更新**
|
||
- 重新整理接口分类,将用户管理接口独立分类
|
||
- 确保文档与实际运行的服务完全一致
|
||
- 验证所有接口的请求参数和响应格式
|
||
- **修复HTTP状态码问题**:所有接口现在根据业务结果返回正确状态码
|
||
- **更新限流配置**:注册接口限制调整为10次/5分钟(开发环境)
|
||
- **应用状态接口** (1个)
|
||
- `GET /` - 获取应用状态
|
||
- **用户认证接口** (13个)
|
||
- 用户登录、注册、GitHub OAuth
|
||
- 密码重置和修改功能
|
||
- 邮箱验证相关接口
|
||
- 调试验证码接口
|
||
- **新增**:清除限流记录接口(开发环境)
|
||
- **管理员接口** (6个)
|
||
- 管理员登录和用户管理
|
||
- 用户列表和详情查询
|
||
- 密码重置功能
|
||
- 日志管理和下载
|
||
- **用户管理接口** (3个)
|
||
- 用户状态管理 (active/inactive/locked/banned/deleted/pending)
|
||
- 单个用户状态修改接口
|
||
- 批量用户状态修改接口
|
||
- 用户状态统计接口
|
||
- **安全增强功能**
|
||
- 频率限制中间件 (Rate Limiting) - 已调整配置
|
||
- 维护模式中间件 (Maintenance Mode)
|
||
- 内容类型验证中间件 (Content Type Validation)
|
||
- 请求超时拦截器 (Request Timeout)
|
||
- 用户状态检查和权限控制
|
||
- **修复**:HTTP状态码现在正确反映业务执行结果
|
||
- **总计接口数量**: 23个API接口
|
||
- 完善错误代码和使用示例
|
||
- 修复路由冲突问题
|
||
- 确保文档与实际测试效果一致
|
||
- **重要修复**:解决了业务失败但返回成功状态码的问题
|
||
|