384 lines
17 KiB
Markdown
384 lines
17 KiB
Markdown
# 用户API
|
||
|
||
<cite>
|
||
**本文引用的文件**
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go)
|
||
- [internal/middleware/auth.go](file://internal/middleware/auth.go)
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go)
|
||
- [internal/service/user_service.go](file://internal/service/user_service.go)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go)
|
||
- [internal/service/verification_service.go](file://internal/service/verification_service.go)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go)
|
||
- [internal/types/common.go](file://internal/types/common.go)
|
||
- [internal/model/response.go](file://internal/model/response.go)
|
||
- [internal/model/user.go](file://internal/model/user.go)
|
||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go)
|
||
- [pkg/config/config.go](file://pkg/config/config.go)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖关系分析](#依赖关系分析)
|
||
7. [性能与安全考量](#性能与安全考量)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本文件面向开发者与集成方,系统化梳理用户管理API,覆盖以下能力:
|
||
- 获取与更新用户个人资料
|
||
- 更换邮箱(基于验证码)
|
||
- 头像上传(通过预签名URL)
|
||
- JWT认证中间件的工作机制
|
||
- 数据结构、请求/响应模式、错误处理与常见问题
|
||
|
||
## 项目结构
|
||
用户相关接口位于统一的路由组“/api/v1/user”,该组下所有端点均受JWT认证保护。认证中间件负责从请求头中提取并校验Bearer Token,并将用户标识写入上下文供业务层使用。
|
||
|
||
```mermaid
|
||
graph TB
|
||
Client["客户端"] --> Routes["路由注册<br/>/api/v1/user/*"]
|
||
Routes --> AuthMW["认证中间件<br/>AuthMiddleware()"]
|
||
AuthMW --> Handlers["用户处理器<br/>user_handler.go"]
|
||
Handlers --> Services["用户服务<br/>user_service.go"]
|
||
Services --> Repos["用户仓储<br/>user_repository.go"]
|
||
Services --> UploadSvc["上传服务<br/>upload_service.go"]
|
||
UploadSvc --> Storage["对象存储客户端<br/>minio.go"]
|
||
Services --> VeriSvc["验证码服务<br/>verification_service.go"]
|
||
Services --> JWT["JWT服务<br/>jwt.go"]
|
||
Services --> Types["类型定义<br/>types/common.go"]
|
||
Handlers --> Models["响应模型<br/>response.go"]
|
||
Handlers --> UserModel["用户模型<br/>model/user.go"]
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L41)
|
||
- [internal/middleware/auth.go](file://internal/middleware/auth.go#L12-L56)
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L416)
|
||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go#L1-L161)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go#L1-L121)
|
||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||
- [internal/model/response.go](file://internal/model/response.go#L1-L86)
|
||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||
|
||
章节来源
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L41)
|
||
|
||
## 核心组件
|
||
- 路由与认证
|
||
- 路由组“/api/v1/user”下的所有端点均使用认证中间件保护。
|
||
- 中间件从Authorization头解析Bearer Token,调用JWT服务进行校验,并将用户ID、用户名、角色写入上下文。
|
||
- 用户处理器
|
||
- 提供获取/更新用户资料、生成头像上传URL、更新头像、更换邮箱等接口。
|
||
- 服务层
|
||
- 用户服务封装业务逻辑(如修改密码、更换邮箱、更新头像),并调用仓储层持久化。
|
||
- 上传服务负责生成预签名URL(POST策略),并构造最终可访问的文件URL。
|
||
- 验证码服务负责生成、发送与校验验证码(更换邮箱场景)。
|
||
- 仓储层
|
||
- 提供用户查询、更新、软删除等基础操作。
|
||
- 类型与模型
|
||
- 统一响应结构、用户信息结构、请求参数结构等。
|
||
- 用户模型包含基本字段及JSONB属性字段。
|
||
|
||
章节来源
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L41)
|
||
- [internal/middleware/auth.go](file://internal/middleware/auth.go#L12-L56)
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L416)
|
||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go#L1-L161)
|
||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L1-L119)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||
- [internal/model/response.go](file://internal/model/response.go#L1-L86)
|
||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||
|
||
## 架构总览
|
||
用户API采用“路由-中间件-处理器-服务-仓储-存储/外部服务”的分层架构。JWT中间件贯穿所有用户相关端点,确保只有合法令牌才能访问。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as "客户端"
|
||
participant R as "路由(/api/v1/user/*)"
|
||
participant M as "认证中间件"
|
||
participant H as "用户处理器"
|
||
participant S as "用户服务"
|
||
participant U as "上传服务"
|
||
participant V as "验证码服务"
|
||
participant D as "仓储"
|
||
participant T as "JWT服务"
|
||
participant O as "对象存储"
|
||
C->>R : "携带Authorization : Bearer <token>"
|
||
R->>M : "进入中间件"
|
||
M->>T : "校验token"
|
||
T-->>M : "Claims(用户ID/用户名/角色)"
|
||
M->>H : "放行,写入上下文"
|
||
alt 获取/更新资料
|
||
H->>S : "GetUserByID/UpdateUserInfo"
|
||
S->>D : "查询/更新"
|
||
D-->>S : "结果"
|
||
S-->>H : "用户信息"
|
||
H-->>C : "200 成功响应"
|
||
else 生成头像上传URL
|
||
H->>U : "GenerateAvatarUploadURL"
|
||
U->>O : "生成预签名POST策略"
|
||
O-->>U : "PostURL+FormData+FileURL"
|
||
U-->>H : "结果"
|
||
H-->>C : "200 成功响应"
|
||
else 更换邮箱
|
||
H->>V : "VerifyCode(验证码)"
|
||
V-->>H : "校验通过/失败"
|
||
H->>S : "ChangeUserEmail"
|
||
S->>D : "更新邮箱"
|
||
D-->>S : "结果"
|
||
S-->>H : "用户信息"
|
||
H-->>C : "200 成功响应"
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L41)
|
||
- [internal/middleware/auth.go](file://internal/middleware/auth.go#L12-L56)
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L416)
|
||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go#L1-L161)
|
||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L1-L119)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go#L1-L121)
|
||
|
||
## 详细组件分析
|
||
|
||
### 认证中间件 AuthMiddleware
|
||
- 功能
|
||
- 从请求头Authorization中解析Bearer token
|
||
- 调用JWT服务校验token有效性
|
||
- 校验通过后将用户ID、用户名、角色写入上下文,供后续处理器使用
|
||
- 异常
|
||
- 缺少Authorization头、格式不正确、token无效时返回401
|
||
- 适用范围
|
||
- 所有“/api/v1/user/*”端点均受此中间件保护
|
||
|
||
章节来源
|
||
- [internal/middleware/auth.go](file://internal/middleware/auth.go#L12-L56)
|
||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||
|
||
### 用户资料:获取与更新
|
||
- 获取用户资料
|
||
- 方法:GET /api/v1/user/profile
|
||
- 认证:需要Bearer token
|
||
- 成功响应:包含用户基本信息(ID、用户名、邮箱、头像、积分、角色、状态、时间戳等)
|
||
- 错误:未授权、用户不存在
|
||
- 更新用户资料
|
||
- 方法:PUT /api/v1/user/profile
|
||
- 认证:需要Bearer token
|
||
- 请求体:支持更新头像URL;若提供新密码,必须同时提供旧密码
|
||
- 成功响应:返回更新后的用户信息
|
||
- 错误:参数错误、未授权、服务器错误、用户不存在
|
||
|
||
章节来源
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L193)
|
||
- [internal/types/common.go](file://internal/types/common.go#L42-L47)
|
||
- [internal/model/response.go](file://internal/model/response.go#L1-L86)
|
||
- [internal/model/user.go](file://internal/model/user.go#L1-L21)
|
||
|
||
### 头像上传流程(预签名URL)
|
||
- 生成上传URL
|
||
- 方法:POST /api/v1/user/avatar/upload-url
|
||
- 认证:需要Bearer token
|
||
- 请求体:文件名(file_name)
|
||
- 成功响应:包含PostURL、FormData、AvatarURL、过期秒数(ExpiresIn)
|
||
- 错误:参数错误、未授权、生成URL失败
|
||
- 上传与确认
|
||
- 客户端使用返回的PostURL与FormData直传至对象存储
|
||
- 上传完成后调用PUT /api/v1/user/avatar,携带avatar_url查询参数
|
||
- 服务端更新用户头像字段并返回最新用户信息
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as "客户端"
|
||
participant H as "用户处理器"
|
||
participant U as "上传服务"
|
||
participant S as "对象存储客户端"
|
||
participant D as "仓储"
|
||
C->>H : "POST /api/v1/user/avatar/upload-url {file_name}"
|
||
H->>U : "GenerateAvatarUploadURL(userID, file_name)"
|
||
U->>S : "生成预签名POST策略"
|
||
S-->>U : "PostURL+FormData+FileURL"
|
||
U-->>H : "返回结果"
|
||
H-->>C : "200 {post_url, form_data, avatar_url, expires_in}"
|
||
C->>S : "使用PostURL+FormData直传"
|
||
S-->>C : "204/201"
|
||
C->>H : "PUT /api/v1/user/avatar?avatar_url=..."
|
||
H->>D : "UpdateUserAvatar"
|
||
D-->>H : "成功"
|
||
H-->>C : "200 用户信息"
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L195-L326)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go#L1-L161)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go#L1-L121)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L126-L130)
|
||
|
||
章节来源
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L195-L326)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go#L1-L161)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go#L1-L121)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L126-L130)
|
||
|
||
### 更换邮箱(验证码)
|
||
- 流程
|
||
- 客户端先向验证码服务发送验证码(此处为通用流程,更换邮箱场景使用特定类型)
|
||
- 调用POST /api/v1/user/change-email,携带新邮箱与验证码
|
||
- 服务端校验验证码,通过后更新用户邮箱并返回最新用户信息
|
||
- 请求体
|
||
- 新邮箱(new_email)
|
||
- 验证码(verification_code)
|
||
- 成功/错误
|
||
- 成功:返回用户信息
|
||
- 错误:参数错误、未授权、验证码错误、邮箱已被占用等
|
||
|
||
章节来源
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L328-L416)
|
||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L1-L119)
|
||
- [internal/service/user_service.go](file://internal/service/user_service.go#L186-L201)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L45-L57)
|
||
|
||
### 数据结构与请求/响应模式
|
||
- 用户信息结构(UserInfo)
|
||
- 字段:id、username、email、avatar、points、role、status、last_login_at、created_at、updated_at
|
||
- 请求体
|
||
- 更新用户:UpdateUserRequest(avatar、old_password、new_password)
|
||
- 生成头像上传URL:GenerateAvatarUploadURLRequest(file_name)
|
||
- 更换邮箱:ChangeEmailRequest(new_email、verification_code)
|
||
- 通用响应
|
||
- 成功:code=200,message=“操作成功”,data为具体数据
|
||
- 失败:code为对应HTTP语义码,message为错误描述,开发环境可带error字段
|
||
|
||
章节来源
|
||
- [internal/types/common.go](file://internal/types/common.go#L42-L47)
|
||
- [internal/types/common.go](file://internal/types/common.go#L62-L67)
|
||
- [internal/types/common.go](file://internal/types/common.go#L68-L80)
|
||
- [internal/model/response.go](file://internal/model/response.go#L1-L86)
|
||
- [internal/model/user.go](file://internal/model/user.go#L1-L21)
|
||
|
||
## 依赖关系分析
|
||
- 路由到处理器
|
||
- /api/v1/user/profile GET/PUT -> GetUserProfile/UpdateUserProfile
|
||
- /api/v1/user/avatar/upload-url POST -> GenerateAvatarUploadURL
|
||
- /api/v1/user/avatar PUT -> UpdateAvatar
|
||
- /api/v1/user/change-email POST -> ChangeEmail
|
||
- 处理器到服务
|
||
- 用户处理器调用用户服务、上传服务、验证码服务
|
||
- 服务到仓储/存储
|
||
- 用户服务调用仓储更新用户信息
|
||
- 上传服务调用对象存储客户端生成预签名URL
|
||
- 中间件到JWT
|
||
- 认证中间件依赖JWT服务校验token并注入用户上下文
|
||
|
||
```mermaid
|
||
graph LR
|
||
Routes["routes.go"] --> Handler["user_handler.go"]
|
||
Handler --> UserService["user_service.go"]
|
||
Handler --> UploadService["upload_service.go"]
|
||
Handler --> VeriService["verification_service.go"]
|
||
UserService --> Repo["user_repository.go"]
|
||
UploadService --> Storage["minio.go"]
|
||
Handler --> Types["types/common.go"]
|
||
Handler --> Resp["response.go"]
|
||
Handler --> ModelUser["model/user.go"]
|
||
AuthMW["auth.go"] --> JWT["jwt.go"]
|
||
Handler --> AuthMW
|
||
```
|
||
|
||
图表来源
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L41)
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L416)
|
||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||
- [internal/service/upload_service.go](file://internal/service/upload_service.go#L1-L161)
|
||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L1-L119)
|
||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||
- [internal/model/response.go](file://internal/model/response.go#L1-L86)
|
||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||
- [internal/middleware/auth.go](file://internal/middleware/auth.go#L12-L56)
|
||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go#L1-L121)
|
||
|
||
## 性能与安全考量
|
||
- 性能
|
||
- 上传采用预签名POST策略,避免服务端中转,降低带宽与延迟
|
||
- 对象存储客户端连接复用,建议合理配置RustFS/Buckets与连接参数
|
||
- 安全
|
||
- 所有用户相关端点强制JWT认证
|
||
- 上传URL带过期时间,防止长期有效链接泄露
|
||
- 验证码更换邮箱,避免暴力破解
|
||
- 密码修改需提供旧密码,防止越权修改
|
||
- 可靠性
|
||
- 上传URL生成失败、验证码校验失败、仓储更新失败均有明确错误返回
|
||
- 建议对高频接口增加限流与熔断策略(可在网关或中间件层实现)
|
||
|
||
[本节为通用指导,不直接分析具体文件]
|
||
|
||
## 故障排查指南
|
||
- 401 未授权
|
||
- 检查Authorization头是否为Bearer token格式
|
||
- 确认token未过期且签名正确
|
||
- 400 参数错误
|
||
- 检查请求体字段是否符合约束(如邮箱格式、验证码长度、文件名等)
|
||
- 404 用户不存在
|
||
- 确认用户ID有效且未被软删除
|
||
- 上传失败
|
||
- 检查生成的PostURL与FormData是否完整
|
||
- 确认对象存储端点、证书、桶名配置正确
|
||
- 验证码错误
|
||
- 检查Redis中验证码是否过期或被提前消费
|
||
- 确认发送频率限制未触发
|
||
|
||
章节来源
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L416)
|
||
- [internal/service/verification_service.go](file://internal/service/verification_service.go#L1-L119)
|
||
- [pkg/storage/minio.go](file://pkg/storage/minio.go#L1-L121)
|
||
- [pkg/config/config.go](file://pkg/config/config.go#L1-L305)
|
||
|
||
## 结论
|
||
本文档系统梳理了用户管理API的路由、认证、数据结构与流程,明确了头像上传与邮箱更换的关键步骤与错误处理策略。建议在生产环境中结合限流、监控与日志体系,持续优化用户体验与系统稳定性。
|
||
|
||
[本节为总结,不直接分析具体文件]
|
||
|
||
## 附录
|
||
|
||
### 接口一览与示例
|
||
- 获取用户资料
|
||
- 方法:GET /api/v1/user/profile
|
||
- 请求:Authorization: Bearer <token>
|
||
- 成功响应:包含UserInfo
|
||
- 更新用户资料
|
||
- 方法:PUT /api/v1/user/profile
|
||
- 请求体:UpdateUserRequest(avatar、old_password、new_password)
|
||
- 成功响应:包含更新后的UserInfo
|
||
- 生成头像上传URL
|
||
- 方法:POST /api/v1/user/avatar/upload-url
|
||
- 请求体:GenerateAvatarUploadURLRequest(file_name)
|
||
- 成功响应:包含post_url、form_data、avatar_url、expires_in
|
||
- 上传头像并确认
|
||
- 方法:PUT /api/v1/user/avatar?avatar_url=...
|
||
- 成功响应:包含UserInfo
|
||
- 更换邮箱
|
||
- 方法:POST /api/v1/user/change-email
|
||
- 请求体:ChangeEmailRequest(new_email、verification_code)
|
||
- 成功响应:包含UserInfo
|
||
|
||
章节来源
|
||
- [internal/handler/routes.go](file://internal/handler/routes.go#L16-L41)
|
||
- [internal/handler/user_handler.go](file://internal/handler/user_handler.go#L17-L416)
|
||
- [internal/types/common.go](file://internal/types/common.go#L42-L47)
|
||
- [internal/types/common.go](file://internal/types/common.go#L62-L67)
|
||
- [internal/types/common.go](file://internal/types/common.go#L68-L80) |