chore(git): 更新.gitignore以忽略新的本地文件
Some checks failed
SonarQube Analysis / sonarqube (push) Has been cancelled

This commit is contained in:
lan
2025-11-30 08:33:17 +08:00
parent 4b4980820f
commit a4b6c5011e
58 changed files with 19353 additions and 0 deletions

View File

@@ -0,0 +1,351 @@
# 用户登录
<cite>
**本文引用的文件**
- [auth_handler.go](file://internal/handler/auth_handler.go)
- [routes.go](file://internal/handler/routes.go)
- [jwt.go](file://pkg/auth/jwt.go)
- [password.go](file://pkg/auth/password.go)
- [user_service.go](file://internal/service/user_service.go)
- [common.go](file://internal/types/common.go)
- [response.go](file://internal/model/response.go)
- [user.go](file://internal/model/user.go)
- [token.go](file://internal/model/token.go)
- [token_service.go](file://internal/service/token_service.go)
- [auth.go](file://internal/middleware/auth.go)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向“用户登录”API围绕 /api/v1/auth/login 端点进行完整说明,覆盖:
- HTTP 方法与路由
- 请求体结构(用户名或邮箱登录)
- 响应格式包含JWT token与用户信息
- 错误码与错误处理
- JWT令牌生成流程访问令牌与声明
- 登录成功/失败后的审计日志记录IP、User-Agent
- 安全建议(防暴力破解、错误提示模糊化)
## 项目结构
该登录流程涉及以下模块协作:
- 路由层:注册 /api/v1/auth/login 路由
- 控制器层:处理登录请求、参数校验、调用服务层
- 服务层:用户查找、密码校验、令牌生成、登录日志记录
- 认证与密码JWT服务、bcrypt密码加解密
- 数据模型:用户、登录日志、令牌
- 中间件JWT认证中间件用于后续受保护接口
```mermaid
graph TB
Client["客户端"] --> Routes["路由注册<br/>/api/v1/auth/login"]
Routes --> Handler["控制器 Login()<br/>参数绑定/错误处理"]
Handler --> Service["服务层 LoginUser()<br/>查找用户/校验密码/生成JWT"]
Service --> JWT["JWT服务 GenerateToken()<br/>签发访问令牌"]
Service --> ModelUser["用户模型 User"]
Service --> ModelLog["登录日志 UserLoginLog"]
Handler --> Resp["统一响应 Response/ErrorResponse"]
Client --> Middleware["认证中间件 AuthMiddleware()<br/>Bearer Token 校验"]
```
图表来源
- [routes.go](file://internal/handler/routes.go#L16-L25)
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [user.go](file://internal/model/user.go#L1-L21)
- [user.go](file://internal/model/user.go#L52-L71)
- [auth.go](file://internal/middleware/auth.go#L12-L56)
章节来源
- [routes.go](file://internal/handler/routes.go#L16-L25)
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
## 核心组件
- 路由与控制器
- /api/v1/auth/login 由控制器 Login 处理负责参数绑定、IP/User-Agent采集、调用服务层并返回统一响应。
- 服务层
- LoginUser 支持用户名或邮箱登录校验用户状态与密码生成JWT更新最后登录时间记录成功/失败日志。
- 认证与密码
- JWT服务提供 GenerateToken/ValidateToken密码使用 bcrypt 进行哈希与校验。
- 数据模型
- User用户信息UserLoginLog登录审计日志Token令牌模型用于后续刷新/失效等场景)。
- 统一响应
- Response/ErrorResponse 提供统一的状态码与消息封装。
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [password.go](file://pkg/auth/password.go#L7-L21)
- [user.go](file://internal/model/user.go#L1-L21)
- [user.go](file://internal/model/user.go#L52-L71)
- [token.go](file://internal/model/token.go#L1-L15)
- [response.go](file://internal/model/response.go#L20-L53)
## 架构总览
登录端到端序列图POST /api/v1/auth/login
```mermaid
sequenceDiagram
participant C as "客户端"
participant R as "路由"
participant H as "控制器 Login()"
participant S as "服务层 LoginUser()"
participant J as "JWT服务"
participant U as "用户模型"
participant L as "登录日志"
C->>R : "POST /api/v1/auth/login"
R->>H : "进入 Login 控制器"
H->>H : "ShouldBindJSON 绑定请求体"
H->>S : "LoginUser(jwtService, username, password, ip, ua)"
S->>U : "根据用户名或邮箱查找用户"
S->>S : "校验用户状态"
S->>S : "bcrypt 校验密码"
S->>J : "GenerateToken(userID, username, role)"
J-->>S : "返回JWT字符串"
S->>U : "更新 last_login_at"
S->>L : "logSuccessLogin/logFailedLogin"
S-->>H : "返回 user, token"
H-->>C : "200 成功响应或401失败响应"
```
图表来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [user.go](file://internal/model/user.go#L1-L21)
- [user.go](file://internal/model/user.go#L52-L71)
## 详细组件分析
### 接口定义与请求/响应
- HTTP 方法与路径
- 方法POST
- 路径:/api/v1/auth/login
- 请求体结构
- 字段username支持用户名或邮箱、password6-128字符
- 参数校验:必填、长度约束
- 响应格式
- 成功统一响应data 包含 token 与 userInfo
- 失败:统一错误响应,包含 code 与 message
- 错误码
- 400请求参数错误
- 401未授权用户名/邮箱或密码错误、账号被禁用等)
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [common.go](file://internal/types/common.go#L27-L31)
- [response.go](file://internal/model/response.go#L20-L53)
### 请求体结构与参数校验
- 请求体字段
- username支持用户名或邮箱
- password6-128字符
- 参数校验
- Gin 绑定时会触发结构体 tag 校验(必填、长度范围)
- 实际行为
- 控制器层在绑定失败时直接返回400
章节来源
- [common.go](file://internal/types/common.go#L27-L31)
- [auth_handler.go](file://internal/handler/auth_handler.go#L101-L109)
### 登录流程与JWT生成
- 登录流程要点
- 识别登录方式:包含@视为邮箱,否则为用户名
- 校验用户状态(仅状态为正常才允许登录)
- 使用 bcrypt 校验密码
- 生成JWT访问令牌包含用户ID、用户名、角色等声明
- 更新最后登录时间
- 记录登录日志(成功/失败均记录IP与User-Agent
- JWT声明内容
- 包含 user_id、username、role
- 默认包含过期时间、签发时间、生效时间、签发者等注册声明
- 令牌有效期
- 由JWT服务配置的过期小时数决定
```mermaid
flowchart TD
Start(["进入 LoginUser"]) --> Detect["判断登录方式<br/>用户名或邮箱"]
Detect --> FindUser["查找用户"]
FindUser --> Status{"用户状态正常?"}
Status -- 否 --> LogFail["记录失败日志<br/>原因:账号被禁用"]
LogFail --> ReturnErr["返回错误"]
Status -- 是 --> CheckPwd["bcrypt 校验密码"]
CheckPwd --> PwdOK{"密码正确?"}
PwdOK -- 否 --> LogFail2["记录失败日志<br/>原因:密码错误"]
LogFail2 --> ReturnErr
PwdOK -- 是 --> GenToken["GenerateToken(userID, username, role)"]
GenToken --> UpdateTime["更新 last_login_at"]
UpdateTime --> LogSuccess["记录成功日志"]
LogSuccess --> Done(["返回 user, token"])
ReturnErr --> Done
```
图表来源
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [password.go](file://pkg/auth/password.go#L16-L21)
- [user.go](file://internal/model/user.go#L1-L21)
- [user.go](file://internal/model/user.go#L52-L71)
章节来源
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [password.go](file://pkg/auth/password.go#L16-L21)
### 响应格式与错误码
- 成功响应
- data包含 token 与 userInfoid、username、email、avatar、points、role、status、last_login_at、created_at、updated_at
- 失败响应
- 400请求参数错误
- 401未授权用户名/邮箱或密码错误、账号被禁用)
- 统一响应封装
- Response/ErrorResponse 提供 code、message、data/error 字段
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L131-L147)
- [common.go](file://internal/types/common.go#L107-L126)
- [response.go](file://internal/model/response.go#L20-L53)
### 登录日志记录IP、User-Agent
- 记录内容
- 成功/失败均记录用户ID、IP地址、User-Agent、登录方式PASSWORD、是否成功、失败原因
- 记录时机
- 成功:登录成功后记录
- 失败:用户不存在、账号禁用、密码错误等情况下记录
- 存储位置
- 写入 user_login_logs 表
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L111-L129)
- [user_service.go](file://internal/service/user_service.go#L203-L226)
- [user.go](file://internal/model/user.go#L52-L71)
### 安全考虑与建议
- 防暴力破解
- 建议在网关或应用层增加速率限制例如基于IP或用户名的限流在失败时延长冷却时间或临时封禁
- 可结合验证码机制(当前登录接口未强制验证码,但注册/重置密码有验证码流程)
- 错误提示模糊化
- 当前服务层对“用户不存在/密码错误/账号禁用”均返回统一的“用户名/邮箱或密码错误”,避免泄露具体原因
- 令牌管理
- 当前登录仅返回JWT访问令牌若需刷新令牌可参考后续令牌服务刷新/失效等)能力
- 传输安全
- 建议仅在HTTPS下提供登录接口防止凭据被窃听
章节来源
- [user_service.go](file://internal/service/user_service.go#L88-L103)
- [auth_handler.go](file://internal/handler/auth_handler.go#L116-L129)
## 依赖关系分析
- 控制器依赖
- 控制器 Login 依赖JWT服务、日志、Redis注册流程、服务层 LoginUser
- 服务层依赖
- LoginUser 依赖用户仓库查找用户、JWT服务生成令牌、密码工具bcrypt、登录日志仓库写入日志
- 认证依赖
- JWT服务依赖golang-jwt库密码工具依赖bcrypt
- 模型依赖
- User、UserLoginLog、Token 模型用于数据持久化与审计
```mermaid
graph LR
H["控制器 Login()"] --> S["服务层 LoginUser()"]
H --> J["JWT服务 GenerateToken()"]
S --> U["User 模型"]
S --> L["UserLoginLog 模型"]
S --> P["bcrypt 密码校验"]
H --> R["路由 RegisterRoutes()"]
M["认证中间件 AuthMiddleware()"] --> J
```
图表来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [password.go](file://pkg/auth/password.go#L16-L21)
- [user.go](file://internal/model/user.go#L1-L21)
- [user.go](file://internal/model/user.go#L52-L71)
- [routes.go](file://internal/handler/routes.go#L16-L25)
- [auth.go](file://internal/middleware/auth.go#L12-L56)
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [user_service.go](file://internal/service/user_service.go#L70-L122)
- [jwt.go](file://pkg/auth/jwt.go#L32-L53)
- [password.go](file://pkg/auth/password.go#L16-L21)
- [user.go](file://internal/model/user.go#L1-L21)
- [user.go](file://internal/model/user.go#L52-L71)
- [routes.go](file://internal/handler/routes.go#L16-L25)
- [auth.go](file://internal/middleware/auth.go#L12-L56)
## 性能考量
- 登录路径涉及数据库查询与密码校验,建议:
- 对用户表建立合适的索引username、email
- 密码校验使用 bcrypt默认成本适中可根据硬件能力调整
- 登录日志写入采用异步或批量策略当前为同步写入注意高并发下的I/O影响
- JWT生成与校验为CPU密集度较低的操作主要瓶颈在数据库与密码校验
## 故障排查指南
- 常见问题与定位
- 400 参数错误:检查请求体字段是否缺失或长度不符合要求
- 401 未授权:核对用户名/邮箱是否存在、账号状态是否正常、密码是否正确
- 登录日志未记录:确认日志写入是否成功,检查数据库连接与表结构
- 日志与审计
- 成功/失败日志均包含 IP 与 User-Agent便于追踪来源设备与来源网络
- 令牌相关
- 若后续引入刷新令牌,可参考令牌服务中的刷新/失效逻辑
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L101-L129)
- [user_service.go](file://internal/service/user_service.go#L203-L226)
- [response.go](file://internal/model/response.go#L20-L53)
## 结论
/api/v1/auth/login 提供了完整的用户名或邮箱登录能力具备参数校验、密码校验、JWT签发与登录日志记录。当前实现聚焦于登录流程本身后续可在速率限制、验证码、刷新令牌等方面进一步增强安全性与可用性。
## 附录
### API定义与示例
- 端点
- 方法POST
- 路径:/api/v1/auth/login
- 请求体
- username字符串必填支持用户名或邮箱
- password字符串必填长度6-128
- 成功响应
- code200
- data包含 token 与 userInfo
- 示例(结构示意)
- data: { token: "...", userInfo: { id, username, email, avatar, points, role, status, last_login_at, created_at, updated_at } }
- 失败响应
- 400请求参数错误
- 401未授权用户名/邮箱或密码错误、账号被禁用)
章节来源
- [auth_handler.go](file://internal/handler/auth_handler.go#L86-L147)
- [common.go](file://internal/types/common.go#L27-L31)
- [common.go](file://internal/types/common.go#L107-L126)
- [response.go](file://internal/model/response.go#L20-L53)
### JWT声明与令牌生命周期
- 声明内容
- user_id、username、role
- 过期时间、签发时间、生效时间、签发者等注册声明
- 令牌类型
- 当前登录返回访问令牌;刷新/失效等能力可参考令牌服务
章节来源
- [jwt.go](file://pkg/auth/jwt.go#L24-L53)
- [token_service.go](file://internal/service/token_service.go#L151-L238)