# 用户服务 **本文引用的文件列表** - [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)