Files
backend/.qoder/repowiki/zh/content/API参考/用户API/个人资料管理.md
lan a4b6c5011e
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
chore(git): 更新.gitignore以忽略新的本地文件
2025-11-30 08:33:17 +08:00

15 KiB
Raw Blame History

个人资料管理

**本文引用的文件** - [user_handler.go](file://internal/handler/user_handler.go) - [routes.go](file://internal/handler/routes.go) - [auth.go](file://internal/middleware/auth.go) - [user_service.go](file://internal/service/user_service.go) - [user_repository.go](file://internal/repository/user_repository.go) - [common.go](file://internal/types/common.go) - [response.go](file://internal/model/response.go) - [user.go](file://internal/model/user.go) - [jwt.go](file://pkg/auth/jwt.go) - [password.go](file://pkg/auth/password.go) - [user_handler_test.go](file://internal/handler/user_handler_test.go)

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向开发者与测试人员系统性梳理“个人资料管理”相关API重点覆盖

  • GET /api/v1/user/profile获取当前登录用户的详细信息
  • PUT /api/v1/user/profile更新头像与密码邮箱修改请使用独立接口

文档将解释 UserInfo 数据结构各字段及 JSON 序列化规则;详述密码更新的安全机制(旧密码校验与新密码加密);说明头像 URL 的更新流程(预签名上传 URL 生成与最终更新)。同时,结合 user_handler.go 中的 GetUserProfile 与 UpdateUserProfile 函数,说明 JWT 中间件如何注入用户上下文,服务层如何调用仓库层执行持久化操作,并提供完整请求/响应示例(含成功与常见错误场景)。

项目结构

围绕个人资料管理的代码组织遵循“控制器-中间件-服务-仓库-模型”的分层设计,路由在 v1 组下统一挂载,用户相关接口均受 JWT 认证保护。

graph TB
Client["客户端"] --> Router["Gin 路由器"]
Router --> GroupV1["/api/v1 用户组<br/>启用 AuthMiddleware()"]
GroupV1 --> GetUserProfile["GET /api/v1/user/profile"]
GroupV1 --> UpdateUserProfile["PUT /api/v1/user/profile"]
GroupV1 --> AvatarUploadURL["POST /api/v1/user/avatar/upload-url"]
GroupV1 --> UpdateAvatar["PUT /api/v1/user/avatar"]
GetUserProfile --> Handler["user_handler.GetUserProfile"]
UpdateUserProfile --> Handler
AvatarUploadURL --> Handler
UpdateAvatar --> Handler
Handler --> Middleware["AuthMiddleware()<br/>注入 user_id/username/role"]
Handler --> Service["user_service.*"]
Service --> Repo["user_repository.*"]
Service --> Model["model.User"]
Handler --> Types["types.UserInfo / UpdateUserRequest"]
Handler --> Resp["model.Response / model.ErrorResponse"]

图表来源

章节来源

核心组件

  • 控制器层Handler
    • GetUserProfile从上下文提取 user_id查询用户并返回 UserInfo
    • UpdateUserProfile接收 UpdateUserRequest按需更新密码与头像返回最新 UserInfo
  • 中间件层AuthMiddleware
    • 解析 Authorization: Bearer ,校验 JWT 并将用户信息写入上下文
  • 服务层Service
    • GetUserByID封装仓库查询
    • UpdateUserInfo / UpdateUserAvatar封装仓库更新
    • ChangeUserPassword校验旧密码并加密新密码后更新
  • 仓库层Repository
    • FindUserByID / UpdateUser / UpdateUserFields数据库读写
  • 类型与模型
    • types.UpdateUserRequest请求体定义
    • types.UserInfo响应体定义
    • model.User数据库映射模型
    • model.Response / model.ErrorResponse统一响应结构

章节来源

架构总览

以下序列图展示“获取/更新用户资料”的端到端流程,包含 JWT 中间件、控制器、服务与仓库的交互。

sequenceDiagram
participant C as "客户端"
participant R as "Gin 路由"
participant M as "AuthMiddleware"
participant H as "user_handler"
participant S as "user_service"
participant RP as "user_repository"
participant DB as "数据库"
C->>R : "GET /api/v1/user/profile"
R->>M : "鉴权中间件"
M-->>R : "注入 user_id/username/role"
R->>H : "GetUserProfile"
H->>S : "GetUserByID(user_id)"
S->>RP : "FindUserByID(user_id)"
RP->>DB : "SELECT ..."
DB-->>RP : "User"
RP-->>S : "User"
S-->>H : "User"
H-->>C : "200 + UserInfo"
C->>R : "PUT /api/v1/user/profile"
R->>M : "鉴权中间件"
M-->>R : "注入 user_id/username/role"
R->>H : "UpdateUserProfile"
H->>H : "解析请求体 UpdateUserRequest"
alt "更新密码"
H->>S : "ChangeUserPassword(user_id, old, new)"
S->>RP : "FindUserByID(user_id)"
RP->>DB : "SELECT ..."
DB-->>RP : "User"
RP-->>S : "User"
S->>S : "CheckPassword(旧密码)"
S->>S : "HashPassword(新密码)"
S->>RP : "UpdateUserFields(user_id, {password})"
RP->>DB : "UPDATE ..."
DB-->>RP : "OK"
end
alt "更新头像"
H->>S : "UpdateUserInfo(User)"
S->>RP : "UpdateUser(User)"
RP->>DB : "SAVE ..."
DB-->>RP : "OK"
end
H->>S : "GetUserByID(user_id)"
S->>RP : "FindUserByID(user_id)"
RP->>DB : "SELECT ..."
DB-->>RP : "User"
RP-->>S : "User"
S-->>H : "User"
H-->>C : "200 + 最新 UserInfo"

图表来源

详细组件分析

GET /api/v1/user/profile获取当前用户资料

  • 功能概述
    • 仅限已登录用户访问,通过 Authorization: Bearer 进行鉴权
    • 中间件将 user_id 写入上下文,控制器据此查询用户并返回 UserInfo
  • 请求与响应
    • 请求Authorization: Bearer
    • 成功响应200 + model.Response{ data: types.UserInfo }
    • 常见错误401 未授权、404 用户不存在
  • 数据结构与序列化
    • types.UserInfo 字段与 JSON 映射规则详见“附录-数据结构”
  • 错误处理
    • 未携带或无效的 Authorization 头:返回 401
    • 查询不到用户:返回 404

章节来源

PUT /api/v1/user/profile更新头像与密码

  • 功能概述
    • 支持同时更新头像 URL 与密码;若仅更新头像,可不提供密码字段
    • 密码更新安全机制:必须同时提供旧密码与新密码,服务层校验旧密码并通过 bcrypt 加密新密码后更新
    • 头像更新流程:先生成预签名上传 URL上传完成后调用更新头像接口最终返回最新 UserInfo
  • 请求体 UpdateUserRequest
    • avatar可选头像 URL
    • old_password可选修改密码时必填
    • new_password可选修改密码时必填
  • 安全机制与流程
    • 旧密码校验:服务层通过 bcrypt 校验
    • 新密码加密:服务层使用 bcrypt 生成哈希
    • 头像更新:控制器直接更新用户记录;若仅更新头像,服务层保存用户对象
  • 错误处理
    • 未授权401
    • 参数错误400如仅提供新密码或仅提供旧密码
    • 用户不存在404
    • 服务器错误500

章节来源

头像上传与更新流程(补充说明)

  • 生成预签名上传 URL
    • POST /api/v1/user/avatar/upload-url
    • 输入file_name
    • 输出post_url、form_data、avatar_url、expires_in
  • 更新头像 URL
    • PUT /api/v1/user/avatar
    • 输入avatar_url查询参数
    • 输出:最新 UserInfo
  • 注意事项
    • 该流程与“更新资料”接口不同,前者用于生成上传凭证,后者用于将最终 URL 写入数据库

章节来源

UserInfo 数据结构与 JSON 序列化规则

  • 字段说明
    • id用户唯一标识
    • username用户名
    • email邮箱
    • avatar头像 URL
    • points积分
    • role角色如 user
    • status账户状态1 正常0 禁用,-1 删除)
    • last_login_at最近登录时间可空
    • created_at / updated_at创建与更新时间
  • JSON 映射
    • model.User 中的 Password 字段在 JSON 中不返回(避免泄露)
    • 其他字段按 gorm 标签映射到 JSON

章节来源

请求/响应示例(含错误场景)

  • 获取资料(成功)
    • 请求Authorization: Bearer
    • 响应200 + { code: 200, message: "操作成功", data: { id, username, email, avatar, points, role, status, last_login_at, created_at, updated_at } }
  • 更新资料(仅更新头像)
  • 更新资料(仅更新密码)
    • 请求体:{ old_password: "...", new_password: "..." }
    • 响应200 + 最新 UserInfo
  • 更新资料(参数错误)
    • 请求体:{ new_password: "..." }(缺少 old_password
    • 响应400 + { code: 400, message: "请求参数错误", error: "修改密码需要提供原密码" }
  • 未授权
    • 请求:未携带或无效 Authorization
    • 响应401 + { code: 401, message: "未授权,请先登录" }
  • 用户不存在
    • 响应404 + { code: 404, message: "资源不存在" }
  • 服务器错误
    • 响应500 + { code: 500, message: "服务器内部错误" }

章节来源

依赖分析

  • 控制器依赖
    • user_handler 依赖 gin 上下文中的 user_id来自 AuthMiddleware
    • 控制器调用 user_service 的 GetUserByID、UpdateUserInfo、ChangeUserPassword、UpdateUserAvatar
  • 服务层依赖
    • user_service 依赖 user_repository 的 FindUserByID、UpdateUser、UpdateUserFields
    • 使用 pkg/auth 的 HashPassword 与 CheckPassword
  • 中间件依赖
    • AuthMiddleware 依赖 pkg/auth/jwt 的 ValidateToken将 claims 写入上下文
  • 模型与类型
    • model.User 作为 ORM 映射
    • types.UserInfo / UpdateUserRequest 作为 API 层数据契约
graph LR
Handler["user_handler"] --> Service["user_service"]
Handler --> Middleware["AuthMiddleware"]
Handler --> Types["types.*"]
Handler --> Resp["model.Response / ErrorResponse"]
Service --> Repo["user_repository"]
Service --> Auth["pkg/auth/*"]
Middleware --> JWT["pkg/auth/jwt"]
Repo --> Model["model.User"]

图表来源

性能考虑

  • 数据库查询
    • GetUserByID 使用精确主键查询,复杂度 O(1),建议保持索引完善
  • 密码处理
    • bcrypt 默认成本较高,建议在高并发场景关注 CPU 开销;可通过配置调整成本值
  • 缓存策略
    • 对频繁读取的用户资料可在应用层引入缓存(如 Redis减少数据库压力
  • 日志与可观测性
    • 控制器与服务层已记录关键错误日志,建议配合链路追踪与指标监控

故障排查指南

  • 401 未授权
    • 检查 Authorization 头是否为 Bearer 格式
    • 确认 token 未过期且签名正确
  • 400 参数错误
    • 密码更新时必须同时提供 old_password 与 new_password
    • 头像 URL 必须为合法 URL
  • 404 用户不存在
    • 确认 user_id 是否有效;检查用户状态是否被禁用或删除
  • 500 服务器错误
    • 检查数据库连接与事务执行情况;查看服务层日志定位具体异常

章节来源

结论

个人资料管理 API 采用清晰的分层架构JWT 中间件负责鉴权并将用户上下文注入控制器,控制器协调服务层完成业务逻辑,服务层通过仓库层与数据库交互。密码更新具备严格的旧密码校验与新密码加密流程,头像更新支持预签名上传与最终 URL 写入。通过统一的响应结构与完善的错误处理,系统在安全性与易用性之间取得平衡。

附录

数据结构与序列化规则

  • types.UserInfo
    • 字段id、username、email、avatar、points、role、status、last_login_at、created_at、updated_at
    • JSON 映射:与 model.User 字段一致,除 password 不返回
  • types.UpdateUserRequest
    • 字段avatar、old_password、new_password
    • 校验:密码更新时 old_password 与 new_password 必须同时提供
  • model.User数据库映射
    • 字段id、username、password、email、avatar、points、role、status、properties、last_login_at、created_at、updated_at
    • JSONpassword 不返回;其他字段按标签映射
  • model.Response / model.ErrorResponse
    • 统一响应结构,包含 code、message、data/error

章节来源