# 用户服务
**本文引用的文件列表**
- [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)
## 目录
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
HTTP接口"]
end
subgraph "服务层"
S["user_service
用户业务逻辑"]
end
subgraph "模型层"
M["user.go
User/UserLoginLog/UserPointLog"]
SCM["system_config.go
SystemConfig"]
end
subgraph "仓储层"
R["user_repository
CRUD/事务"]
SCR["system_config_repository
系统配置查询"]
end
subgraph "认证与工具"
P["password.go
密码加解密"]
J["jwt.go
JWT签发/校验"]
T["types/common.go
请求/响应结构"]
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)