chore(git): 更新.gitignore以忽略新的本地文件
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled
This commit is contained in:
372
.qoder/repowiki/zh/content/服务架构/用户服务.md
Normal file
372
.qoder/repowiki/zh/content/服务架构/用户服务.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# 用户服务
|
||||
|
||||
<cite>
|
||||
**本文引用的文件列表**
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go)
|
||||
- [internal/model/user.go](file://internal/model/user.go)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go)
|
||||
- [internal/types/common.go](file://internal/types/common.go)
|
||||
- [internal/service/common.go](file://internal/service/common.go)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go)
|
||||
- [internal/model/system_config.go](file://internal/model/system_config.go)
|
||||
- [internal/service/user_service_test.go](file://internal/service/user_service_test.go)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件聚焦于用户服务(UserService)的职责、方法与内部逻辑,覆盖用户注册、登录、信息更新等核心功能,并对默认角色、状态与积分的初始化进行说明;同时解释头像选择策略(优先自定义头像,否则使用默认头像)以及数据验证规则(用户名、邮箱、密码非空且邮箱格式正确)。文档还提供服务层与仓储层的调用关系示例,帮助初学者理解业务流程,并为有经验的开发者提供扩展点建议(如修改默认角色、添加新的用户属性)。
|
||||
|
||||
## 项目结构
|
||||
用户服务位于 internal/service 层,围绕 internal/model 定义的数据模型工作,通过 internal/repository 与数据库交互,对外由 internal/handler 提供 HTTP 接口。认证相关的密码处理与 JWT 令牌生成分别由 pkg/auth 下的 password 与 jwt 组件完成。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "接口层"
|
||||
H["auth_handler<br/>HTTP接口"]
|
||||
end
|
||||
subgraph "服务层"
|
||||
S["user_service<br/>用户业务逻辑"]
|
||||
end
|
||||
subgraph "模型层"
|
||||
M["user.go<br/>User/UserLoginLog/UserPointLog"]
|
||||
SCM["system_config.go<br/>SystemConfig"]
|
||||
end
|
||||
subgraph "仓储层"
|
||||
R["user_repository<br/>CRUD/事务"]
|
||||
SCR["system_config_repository<br/>系统配置查询"]
|
||||
end
|
||||
subgraph "认证与工具"
|
||||
P["password.go<br/>密码加解密"]
|
||||
J["jwt.go<br/>JWT签发/校验"]
|
||||
T["types/common.go<br/>请求/响应结构"]
|
||||
end
|
||||
H --> S
|
||||
S --> R
|
||||
S --> SCR
|
||||
S --> P
|
||||
S --> J
|
||||
S --> M
|
||||
S --> SCM
|
||||
T --> H
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L1-L250)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||||
|
||||
章节来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L1-L250)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||||
|
||||
## 核心组件
|
||||
- 用户模型(User):包含用户名、邮箱、头像、积分、角色、状态、最后登录时间等字段,以及唯一索引约束与默认值。
|
||||
- 用户登录日志(UserLoginLog):记录登录尝试的IP、UA、是否成功及失败原因。
|
||||
- 用户积分日志(UserPointLog):记录积分变动明细(类型、金额、前后余额、原因等)。
|
||||
- 系统配置(SystemConfig):键值型配置,用于存储默认头像等全局设置。
|
||||
- 服务层(UserService):封装注册、登录、信息更新、头像更新、密码修改/重置、邮箱变更等业务逻辑。
|
||||
- 仓储层(UserRepository):提供用户与登录/积分日志的数据库操作,包含事务性积分更新。
|
||||
- 认证工具(Password/JWT):密码加密与校验、JWT签发与校验。
|
||||
- 接口层(AuthHandler):接收HTTP请求,绑定参数,调用服务层并返回统一响应。
|
||||
|
||||
章节来源
|
||||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L1-L250)
|
||||
|
||||
## 架构总览
|
||||
下图展示从HTTP请求到服务层再到仓储层的整体调用链路,以及关键对象之间的关系。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant H as "AuthHandler"
|
||||
participant S as "UserService"
|
||||
participant P as "Password"
|
||||
participant J as "JWTService"
|
||||
participant R as "UserRepository"
|
||||
participant SCR as "SystemConfigRepository"
|
||||
C->>H : "POST /api/v1/auth/register"
|
||||
H->>H : "绑定RegisterRequest并校验"
|
||||
H->>S : "RegisterUser(jwtService, username, password, email, avatar)"
|
||||
S->>R : "FindUserByUsername(username)"
|
||||
S->>R : "FindUserByEmail(email)"
|
||||
S->>P : "HashPassword(password)"
|
||||
S->>SCR : "GetSystemConfigByKey('default_avatar')"
|
||||
S->>R : "CreateUser(user)"
|
||||
S->>J : "GenerateToken(user.id, user.username, user.role)"
|
||||
S-->>H : "返回user, token"
|
||||
H-->>C : "返回LoginResponse"
|
||||
C->>H : "POST /api/v1/auth/login"
|
||||
H->>S : "LoginUser(jwtService, usernameOrEmail, password, ip, ua)"
|
||||
S->>R : "按用户名或邮箱查找用户"
|
||||
S->>S : "检查用户状态"
|
||||
S->>P : "CheckPassword(user.password, password)"
|
||||
S->>R : "UpdateUserFields(last_login_at)"
|
||||
S->>J : "GenerateToken(...)"
|
||||
S-->>H : "返回user, token"
|
||||
H-->>C : "返回LoginResponse"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L1-L250)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 用户服务(UserService)职责与方法
|
||||
- 注册(RegisterUser)
|
||||
- 校验用户名与邮箱唯一性
|
||||
- 密码加密
|
||||
- 头像选择:若传入自定义头像则使用,否则从系统配置读取默认头像
|
||||
- 初始化角色为“user”,状态为1(正常),积分初始为0
|
||||
- 创建用户并生成JWT
|
||||
- 登录(LoginUser)
|
||||
- 支持用户名或邮箱登录(通过是否包含“@”判断)
|
||||
- 校验用户状态(仅允许状态为1的用户登录)
|
||||
- 验证密码
|
||||
- 生成JWT并更新最后登录时间
|
||||
- 记录登录日志(成功/失败)
|
||||
- 查询与更新
|
||||
- 按ID获取用户
|
||||
- 更新用户信息(完整保存)
|
||||
- 更新头像(字段更新)
|
||||
- 修改密码(校验旧密码后加密新密码并更新)
|
||||
- 重置密码(通过邮箱查找用户并更新密码)
|
||||
- 更换邮箱(校验新邮箱唯一性后更新)
|
||||
|
||||
章节来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
|
||||
### 数据模型与默认值
|
||||
- 用户模型字段与默认值
|
||||
- 角色:默认“user”
|
||||
- 状态:默认1(正常)
|
||||
- 积分:默认0
|
||||
- 头像:默认空字符串
|
||||
- 时间戳:createdAt/updatedAt默认当前时间
|
||||
- 登录日志与积分日志
|
||||
- 登录日志包含IP、UA、登录方式、是否成功、失败原因
|
||||
- 积分日志包含变更类型、金额、前后余额、原因等
|
||||
|
||||
章节来源
|
||||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||||
|
||||
### 头像逻辑(默认头像策略)
|
||||
- 优先使用用户提供的头像URL
|
||||
- 若未提供,则从系统配置中读取键为“default_avatar”的值作为默认头像
|
||||
- 若系统配置不存在,则返回提示信息字符串
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["开始"]) --> CheckProvided["是否提供了头像URL?"]
|
||||
CheckProvided --> |是| UseProvided["使用提供的头像URL"]
|
||||
CheckProvided --> |否| LoadConfig["从系统配置读取default_avatar"]
|
||||
LoadConfig --> Found{"配置是否存在?"}
|
||||
Found --> |是| UseDefault["使用系统配置中的默认头像URL"]
|
||||
Found --> |否| UseError["返回默认头像配置缺失提示"]
|
||||
UseProvided --> End(["结束"])
|
||||
UseDefault --> End
|
||||
UseError --> End
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L228-L240)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L23)
|
||||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||||
|
||||
章节来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L228-L240)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L23)
|
||||
- [internal/model/system_config.go](file://internal/model/system_config.go#L1-L42)
|
||||
|
||||
### 数据验证规则
|
||||
- 请求体绑定规则(由接口层负责)
|
||||
- 注册:用户名必填且长度在3-50之间,邮箱必填且符合邮箱格式,密码必填且长度6-128,验证码必填且长度6,头像可选且需为合法URL
|
||||
- 登录:用户名必填(支持用户名或邮箱),密码必填且长度6-128
|
||||
- 更新用户:头像可选且为合法URL,修改密码时旧密码与新密码长度要求
|
||||
- 服务层内部验证
|
||||
- 注册时对用户名、邮箱、密码进行基本非空与邮箱格式校验
|
||||
- 登录时对状态进行检查,密码进行校验
|
||||
- 更换邮箱时确保新邮箱未被他人使用
|
||||
|
||||
章节来源
|
||||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/service/user_service_test.go](file://internal/service/user_service_test.go#L1-L200)
|
||||
|
||||
### 服务层与仓储层调用关系示例
|
||||
- 注册流程
|
||||
- Handler -> UserService.RegisterUser -> UserRepository.FindUserByUsername/ByEmail -> Password.HashPassword -> SystemConfigRepository.GetSystemConfigByKey -> UserRepository.CreateUser -> JWTService.GenerateToken
|
||||
- 登录流程
|
||||
- Handler -> UserService.LoginUser -> UserRepository.FindUserByUsername/ByEmail -> Password.CheckPassword -> UserRepository.UpdateUserFields -> JWTService.GenerateToken
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AuthHandler {
|
||||
+Register()
|
||||
+Login()
|
||||
}
|
||||
class UserService {
|
||||
+RegisterUser(...)
|
||||
+LoginUser(...)
|
||||
+GetUserByID(...)
|
||||
+UpdateUserInfo(...)
|
||||
+UpdateUserAvatar(...)
|
||||
+ChangeUserPassword(...)
|
||||
+ResetUserPassword(...)
|
||||
+ChangeUserEmail(...)
|
||||
}
|
||||
class UserRepository {
|
||||
+CreateUser(...)
|
||||
+FindUserByID(...)
|
||||
+FindUserByUsername(...)
|
||||
+FindUserByEmail(...)
|
||||
+UpdateUser(...)
|
||||
+UpdateUserFields(...)
|
||||
+CreateLoginLog(...)
|
||||
+UpdateUserPoints(...)
|
||||
}
|
||||
class SystemConfigRepository {
|
||||
+GetSystemConfigByKey(...)
|
||||
}
|
||||
class Password {
|
||||
+HashPassword(...)
|
||||
+CheckPassword(...)
|
||||
}
|
||||
class JWTService {
|
||||
+GenerateToken(...)
|
||||
+ValidateToken(...)
|
||||
}
|
||||
AuthHandler --> UserService : "调用"
|
||||
UserService --> UserRepository : "CRUD/事务"
|
||||
UserService --> SystemConfigRepository : "读取默认头像"
|
||||
UserService --> Password : "密码处理"
|
||||
UserService --> JWTService : "签发Token"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L1-L250)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
|
||||
## 依赖分析
|
||||
- 内部依赖
|
||||
- UserService 依赖 UserRepository、SystemConfigRepository、Password、JWTService、User模型、SystemConfig模型
|
||||
- AuthHandler 依赖 UserService、Types(请求/响应)、Logger、Redis(验证码)、Email(发送验证码)
|
||||
- 外部依赖
|
||||
- bcrypt 用于密码加密与校验
|
||||
- golang-jwt/jwt/v5 用于JWT签发与校验
|
||||
- GORM 用于数据库访问与事务
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
H["AuthHandler"] --> S["UserService"]
|
||||
S --> R["UserRepository"]
|
||||
S --> SCR["SystemConfigRepository"]
|
||||
S --> P["Password(bcrypt)"]
|
||||
S --> J["JWTService(gojwt)"]
|
||||
S --> M["User/SystemConfig Models"]
|
||||
R --> DB["GORM/DB"]
|
||||
SCR --> DB
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [internal/handler/auth_handler.go](file://internal/handler/auth_handler.go#L1-L250)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [internal/repository/system_config_repository.go](file://internal/repository/system_config_repository.go#L1-L58)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
|
||||
章节来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/repository/user_repository.go](file://internal/repository/user_repository.go#L1-L137)
|
||||
- [pkg/auth/password.go](file://pkg/auth/password.go#L1-L21)
|
||||
- [pkg/auth/jwt.go](file://pkg/auth/jwt.go#L1-L71)
|
||||
|
||||
## 性能考虑
|
||||
- 密码加密成本:bcrypt 默认成本较高,建议在高并发场景下关注注册/登录的延迟,必要时评估成本参数与异步化策略
|
||||
- 数据库索引:用户名与邮箱字段具备唯一索引,有助于快速去重;登录日志与积分日志按时间建立索引,有利于查询与统计
|
||||
- 事务一致性:积分变更采用事务,避免并发写入导致的余额不一致
|
||||
- 缓存策略:默认头像配置可考虑缓存以减少数据库查询次数
|
||||
|
||||
## 故障排查指南
|
||||
- 注册失败
|
||||
- 检查用户名/邮箱是否重复
|
||||
- 确认密码加密是否成功
|
||||
- 检查系统配置中是否存在“default_avatar”
|
||||
- 登录失败
|
||||
- 用户不存在或状态非1
|
||||
- 密码校验失败
|
||||
- 检查IP与User-Agent是否正确传入
|
||||
- 头像显示异常
|
||||
- 自定义头像URL是否有效
|
||||
- 系统默认头像配置是否正确
|
||||
- 集成测试参考
|
||||
- 单元测试覆盖了默认头像逻辑、邮箱检测、常量与验证逻辑,可据此定位问题
|
||||
|
||||
章节来源
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/service/user_service_test.go](file://internal/service/user_service_test.go#L1-L200)
|
||||
|
||||
## 结论
|
||||
UserService 以清晰的职责划分实现了用户生命周期管理:从注册、登录到信息维护与安全控制。通过明确的默认值与验证规则,结合仓储层的事务与模型层的结构化设计,系统在保证安全性的同时具备良好的可扩展性。对于扩展需求,可在服务层增加新的默认值或属性映射,并在仓储层补充相应的查询/更新逻辑。
|
||||
|
||||
## 附录
|
||||
|
||||
### 扩展点指导
|
||||
- 修改默认角色
|
||||
- 在注册流程中调整角色初始化值
|
||||
- 若需动态分配角色,可引入系统配置或权限策略模块
|
||||
- 添加新的用户属性
|
||||
- 在 User 模型中新增字段并设置默认值
|
||||
- 在注册流程中初始化该字段
|
||||
- 在接口层的请求/响应结构中同步新增字段
|
||||
- 默认积分初始化
|
||||
- 当前初始积分为0,可通过系统配置读取或硬编码调整
|
||||
- 注册奖励积分可作为后续增强点(服务层已有TODO标记)
|
||||
|
||||
章节来源
|
||||
- [internal/model/user.go](file://internal/model/user.go#L1-L71)
|
||||
- [internal/service/user_service.go](file://internal/service/user_service.go#L1-L249)
|
||||
- [internal/types/common.go](file://internal/types/common.go#L1-L215)
|
||||
- [internal/service/common.go](file://internal/service/common.go#L1-L14)
|
||||
Reference in New Issue
Block a user