Files
user-system/docs/architecture-design.md
long-agent 2a18a6fb47 fix(n+1): 批量查询替代循环单查
- IsAdminBootstrapRequired: userRepo.GetByID 循环 → GetByIDs 批量
- AssignRoles: roleRepo.GetByID 循环 → GetByIDs 批量
- 在 userRepositoryInterface 补充 GetByIDs 方法签名
2026-05-08 08:05:26 +08:00

827 lines
44 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 用户管理系统架构设计文档
> 版本v1.0
> 更新日期2026-05-07
> 适用范围UMS (User Management System)
---
## 1. 技术栈与框架选型
### 1.1 后端技术栈
| 层级 | 技术选型 | 版本/说明 |
|------|---------|----------|
| **开发语言** | Go | 1.21+,高性能、原生并发、低内存占用 |
| **Web 框架** | Gin | 轻量级、高性能 HTTP 路由与中间件 |
| **ORM / 数据库** | GORM | 支持 PostgreSQL / SQLite / MySQL自动迁移 |
| **缓存** | Redis (go-redis) | 可选启用,分布式会话与热点缓存 |
| **本地缓存** | 自研 LocalCache | 内存 L1 缓存TTL + 后台清理 |
| **配置管理** | Viper | YAML + 环境变量统一配置 |
| **日志** | Zap | 高性能结构化日志 |
| **JWT** | golang-jwt/jwt | RS256 签名,支持 JTI 与 Token 滚动轮换 |
| **密码哈希** | golang.org/x/crypto/argon2 | Argon2id启动时自适应校准 |
| **TOTP 2FA** | github.com/pquerna/otp | RFC 6238 兼容 |
| **监控** | Prometheus + OpenTelemetry | 指标采集与链路追踪 |
| **限流** | Uber Rate Limit / 自研 | 令牌桶 + 内存清理 |
| **容器化** | Docker | 单容器 + Docker Compose 编排 |
| **编排(可选)** | Kubernetes | 生产集群部署 |
### 1.2 前端技术栈Admin 后台)
| 层级 | 技术选型 | 说明 |
|------|---------|------|
| **框架** | React 18 + TypeScript | 类型安全、组件化开发 |
| **构建工具** | Vite | 快速冷启动与热更新 |
| **UI 组件库** | Ant Design 5 | 企业级后台组件 |
| **状态管理** | React Context会话态 | 不引入重型状态库 |
| **HTTP 客户端** | 原生 `fetch` + 统一请求客户端 | 无 Axios 依赖 |
| **路由** | React Router 6 | 受保护路由方案 |
| **样式** | CSS Modules + CSS Variables + AntD Theme Token | 无 styled-components |
### 1.3 基础设施
| 组件 | 技术选型 | 说明 |
|------|---------|------|
| **负载均衡** | Nginx | 反向代理、SSL 终止、静态资源缓存 |
| **消息队列(可选)** | Kafka / RabbitMQ | 异步事件、Webhook 投递 |
| **对象存储(可选)** | OSS / S3 | 头像与文件上传 |
| **监控大盘** | Grafana | 可视化 Prometheus 指标 |
| **日志收集** | ELK / Loki | 集中化日志检索 |
---
## 2. 目录结构与分层说明
项目采用 **Clean Architecture** 分层,依赖方向始终向内:
```
handler → service → repository → domain
```
### 2.1 目录结构
```
├── cmd/
│ ├── server/ # HTTP 服务入口
│ └── ums/ # CLI 工具入口
├── internal/
│ ├── api/
│ │ ├── handler/ # HTTP 请求处理器 (Handler 层)
│ │ ├── middleware/ # Gin 中间件认证、限流、日志、CORS 等)
│ │ └── router/ # 路由注册与分组
│ ├── auth/
│ │ └── providers/ # OAuth2 Provider 实现
│ ├── cache/ # 本地缓存 + Redis 封装
│ ├── concurrent/ # 并发工具WorkerPool、SingleFlight
│ ├── config/ # 配置结构与加载
│ ├── database/ # GORM 初始化、连接池、读写分离
│ ├── domain/ # 领域实体User、Role、Permission 等)
│ ├── e2e/ # 端到端测试
│ ├── integration/ # 集成测试
│ ├── middleware/ # 共享中间件(与 api/middleware 区分)
│ ├── monitoring/ # Prometheus 指标与链路追踪
│ ├── pagination/ # 游标分页与 OFFSET 分页封装
│ ├── performance/ # 性能测试与基准测试
│ ├── pkg/ # 内部公共包
│ │ ├── errors/ # 错误码与错误包装
│ │ ├── ip/ # IP 解析与过滤
│ │ ├── oauth/ # OAuth2 辅助工具
│ │ └── ...
│ ├── repository/ # 数据访问层Repository 层)
│ ├── robustness/ # 鲁棒性工具(熔断、重试)
│ ├── security/ # 安全工具(密码策略、加密、校验)
│ ├── server/ # HTTP Server 生命周期管理
│ ├── service/ # 业务逻辑层Service 层)
│ ├── testdb/ # 测试数据库辅助
│ ├── testutil/ # 测试工具函数
│ └── util/ # 通用工具包
├── pkg/
│ └── errors/ # 对外暴露的错误包
├── configs/
│ └── config.yaml # 默认配置文件
├── deployments/
│ ├── docker-compose.yml # 本地编排
│ └── kubernetes/ # K8s 清单
├── docs/ # 设计文档与 API 文档
├── frontend/ # React Admin 前端(独立目录)
├── migrations/ # 数据库迁移脚本
├── scripts/ # 构建与运维脚本
├── sdk/ # 客户端 SDK
├── uploads/ # 本地上传文件存储(受保护)
└── tools/ # 开发工具
```
### 2.2 分层职责
| 分层 | 目录 | 职责 | 依赖规则 |
|------|------|------|----------|
| **Handler 层** | `internal/api/handler` | HTTP 请求解析、参数校验、响应封装、调用 Service | 仅依赖 Service 层 |
| **Service 层** | `internal/service` | 业务逻辑编排、事务管理、领域事件触发 | 仅依赖 Repository 与 Domain |
| **Repository 层** | `internal/repository` | 数据持久化、查询优化、ORM 操作 | 仅依赖 Domain |
| **Domain 层** | `internal/domain` | 实体定义、值对象、领域规则、接口契约 | 不依赖任何外部层 |
| **基础设施层** | `internal/cache`, `internal/database`, `internal/config` | 技术实现(缓存、数据库、配置) | 可被上层通过接口注入 |
---
## 3. 核心模块架构图
### 3.1 整体模块交互
```
┌─────────────────────────────────────────────────────────────────────┐
│ 外部客户端 │
│ (Web Admin / Mobile App / 第三方 OAuth / SDK 调用方) │
└───────────────────────────────┬─────────────────────────────────────┘
┌───────────────────────────────▼─────────────────────────────────────┐
│ API 网关层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 认证中间件 │ │ 限流中间件 │ │ 日志中间件 │ │
│ │ (JWT/OAuth2) │ │ (RateLimit) │ │ (AccessLog) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ CORS 中间件 │ │ CSRF 中间件 │ │ IP 过滤中间件 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
┌───────────────────────────────▼─────────────────────────────────────┐
│ Handler 层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Auth │ │ User │ │ Role │ │ Device │ │ Log │ │
│ │ Handler │ │ Handler │ │ Handler │ │ Handler │ │ Handler │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Admin │ │ Webhook │ │ 2FA │ │ OAuth │ │
│ │ Handler │ │ Handler │ │ Handler │ │ Handler │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
┌───────────────────────────────▼─────────────────────────────────────┐
│ Service 层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Auth │ │ User │ │ Role │ │ Device │ │ Log │ │
│ │ Service │ │ Service │ │ Service │ │ Service │ │ Service │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Admin │ │ Webhook │ │ 2FA │ │ OAuth │ │
│ │ Service │ │ Service │ │ Service │ │ Service │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
┌───────────────────────────────▼─────────────────────────────────────┐
│ Repository 层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ UserRepo │ │ RoleRepo │ │ PermRepo │ │ DevRepo │ │ LogRepo │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Social │ │ Password │ │ Webhook │ │
│ │ Repo │ │ History │ │ Repo │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└───────────────────────────────┬─────────────────────────────────────┘
┌───────────────────────────────▼─────────────────────────────────────┐
│ Domain 层 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ User │ │ Role │ │ Permission│ │ Device │ │ LoginLog │ │
│ │ Entity │ │ Entity │ │ Entity │ │ Entity │ │ Entity │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Operation│ │ Webhook │ │ Password │ │
│ │ Log │ │ Entity │ │ History │ │
│ │ Entity │ │ │ │ Entity │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────┘
```
### 3.2 请求处理流程
| 步骤 | 组件 | 动作 |
|------|------|------|
| 1 | Nginx / Ingress | SSL 终止、静态资源缓存、反向代理 |
| 2 | Gin Router | 路由匹配、路径参数解析 |
| 3 | Middleware Chain | 限流 → IP 过滤 → CORS → CSRF → 认证 → 日志 |
| 4 | Handler | 绑定请求体、参数校验、调用 Service |
| 5 | Service | 业务逻辑、权限检查、事务封装 |
| 6 | Repository | ORM 查询 / 写入、缓存读写 |
| 7 | Database / Cache | 数据持久化或缓存命中 |
| 8 | Service | 组装领域结果、触发异步事件Webhook、日志 |
| 9 | Handler | 统一响应封装code / message / data |
| 10 | Middleware | 记录访问日志、更新 Prometheus 指标 |
### 3.3 核心模块职责表
| 模块 | 职责 | 关键文件/包 |
|------|------|------------|
| **认证 (Auth)** | 注册、登录、登出、JWT 签发与刷新、密码重置、TOTP | `internal/auth`, `internal/api/handler/auth_handler.go` |
| **用户 (User)** | CRUD、头像上传、状态管理、角色分配、导入导出 | `internal/service/user_service.go`, `internal/repository/user_repository.go` |
| **RBAC** | 角色管理、权限管理、角色继承、权限树 | `internal/domain/role.go`, `internal/service/role_service.go` |
| **设备 (Device)** | 设备注册、信任管理、多设备登出 | `internal/api/handler/device_handler.go` |
| **日志 (Log)** | 登录日志、操作日志、查询与审计 | `internal/repository/log_repository.go` |
| **OAuth2** | 第三方登录、社交账号绑定/解绑 | `internal/auth/providers/` |
| **Webhook** | 事件订阅、异步投递、重试机制 | `internal/service/webhook_service.go` |
| **Admin** | 仪表盘统计、批量导入导出 | `internal/api/handler/admin_handler.go` |
| **安全 (Security)** | 密码策略、IP 过滤、敏感数据脱敏 | `internal/security/` |
---
## 4. 数据模型
### 4.1 实体关系总览
```
users ||--o{ user_roles : "多对多"
users ||--o{ devices : "一对多"
users ||--o{ login_logs : "一对多"
users ||--o{ operation_logs : "一对多"
users ||--o{ user_social_accounts : "一对多"
users ||--o{ password_history : "一对多"
roles ||--o{ user_roles : "多对多"
roles ||--o{ role_permissions : "多对多"
roles ||--o{ roles : "自关联(继承)"
permissions ||--o{ role_permissions : "多对多"
webhooks ||--o{ webhook_deliveries : "一对多"
```
### 4.2 核心实体定义
#### User用户
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGINT | PK, AutoIncrement | 用户唯一标识 |
| username | VARCHAR(50) | UNIQUE, Index | 用户名 |
| email | VARCHAR(100) | UNIQUE, Index | 邮箱地址 |
| phone | VARCHAR(20) | UNIQUE, Index | 手机号 |
| password | VARCHAR(255) | Not Null | Argon2id 哈希密码 |
| nickname | VARCHAR(50) | Nullable | 昵称 |
| avatar | VARCHAR(255) | Nullable | 头像 URL |
| gender | TINYINT | Default 0 | 性别0-未知1-男2-女 |
| birthday | DATE | Nullable | 生日 |
| region | VARCHAR(50) | Nullable | 所在地区 |
| bio | VARCHAR(500) | Nullable | 个性签名 |
| status | TINYINT | Default 1, Index | 状态0-待激活1-正常2-锁定3-禁用 |
| totp_secret | VARCHAR(255) | Nullable | TOTP 密钥(加密存储) |
| totp_enabled | TINYINT | Default 0 | 是否启用 TOTP |
| password_changed_at | DATETIME | Nullable | 密码最后修改时间(用于 Token 失效) |
| last_login_time | DATETIME | Nullable | 最后登录时间 |
| last_login_ip | VARCHAR(50) | Nullable | 最后登录 IP |
| created_at | DATETIME | Default CURRENT_TIMESTAMP | 创建时间 |
| updated_at | DATETIME | AutoUpdate | 更新时间 |
| deleted_at | DATETIME | Nullable, Index | 软删除时间GORM 支持) |
**索引**`uk_username`, `uk_email`, `uk_phone`, `idx_status`, `idx_created_at`
#### Role角色
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGINT | PK, AutoIncrement | 角色唯一标识 |
| name | VARCHAR(50) | UNIQUE, Not Null | 角色名称 |
| code | VARCHAR(50) | UNIQUE, Not Null | 角色代码(如 `admin`, `user` |
| description | VARCHAR(200) | Nullable | 角色描述 |
| parent_id | BIGINT | FK → roles.id, Nullable | 父角色 ID继承关系 |
| level | INT | Default 1, Index | 角色层级 |
| is_system | TINYINT | Default 0 | 是否系统内置角色 |
| is_default | TINYINT | Default 0, Index | 是否新用户默认角色 |
| status | TINYINT | Default 1 | 状态0-禁用1-启用 |
| created_at | DATETIME | Default CURRENT_TIMESTAMP | 创建时间 |
| updated_at | DATETIME | AutoUpdate | 更新时间 |
**索引**`uk_name`, `uk_code`, `idx_parent_id`, `idx_level`
**初始数据**
- `id=1, code='admin', name='管理员', is_system=1` —— 系统管理员
- `id=2, code='user', name='普通用户', is_system=1, is_default=1` —— 默认用户
#### Permission权限
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGINT | PK, AutoIncrement | 权限唯一标识 |
| name | VARCHAR(50) | Not Null | 权限名称 |
| code | VARCHAR(100) | UNIQUE, Not Null | 权限代码(格式 `resource:action` |
| resource | VARCHAR(50) | Not Null, Index | 资源名称(如 `user`, `role` |
| action | VARCHAR(20) | Not Null | 操作类型:`read` / `write` / `delete` / `execute` |
| description | VARCHAR(200) | Nullable | 权限描述 |
| type | VARCHAR(20) | Not Null, Index | 权限类型:`api` / `page` / `button` |
| group_id | BIGINT | Nullable, Index | 权限分组 ID |
| status | TINYINT | Default 1 | 状态0-禁用1-启用 |
| created_at | DATETIME | Default CURRENT_TIMESTAMP | 创建时间 |
| updated_at | DATETIME | AutoUpdate | 更新时间 |
**索引**`uk_code`, `idx_resource`, `idx_group_id`
#### Device设备
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGINT | PK, AutoIncrement | 设备唯一标识 |
| user_id | BIGINT | FK → users.id, Not Null, Index | 所属用户 |
| device_id | VARCHAR(100) | UNIQUE, Not Null | 设备唯一标识字符串 |
| device_name | VARCHAR(50) | Nullable | 设备名称 |
| device_type | VARCHAR(20) | Not Null | 设备类型:`pc` / `mobile` / `tablet` |
| os | VARCHAR(50) | Nullable | 操作系统 |
| browser | VARCHAR(50) | Nullable | 浏览器 |
| ip | VARCHAR(50) | Nullable | 最近 IP |
| location | VARCHAR(100) | Nullable | 地理位置 |
| is_trusted | TINYINT | Default 0 | 是否信任设备(跳过 2FA |
| trust_expires_at | DATETIME | Nullable | 信任状态过期时间 |
| last_active_time | DATETIME | Nullable, Index | 最后活跃时间 |
| created_at | DATETIME | Default CURRENT_TIMESTAMP | 创建时间 |
**索引**`idx_user_id`, `uk_device_id`, `idx_last_active_time`
#### LoginLog登录日志
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGINT | PK, AutoIncrement | 日志唯一标识 |
| user_id | BIGINT | FK → users.id, Nullable, Index | 用户 ID匿名登录为 NULL |
| login_type | VARCHAR(20) | Not Null | 登录方式:`password` / `code` / `wechat` / `github` / ... |
| login_method | VARCHAR(20) | Nullable | 认证子方式 |
| ip | VARCHAR(50) | Nullable, Index | 登录 IP |
| location | VARCHAR(100) | Nullable | 地理位置 |
| device_id | VARCHAR(100) | Nullable | 设备标识 |
| user_agent | VARCHAR(500) | Nullable | User-Agent |
| status | TINYINT | Not Null, Index | 状态0-失败1-成功 |
| failure_reason | VARCHAR(200) | Nullable | 失败原因 |
| created_at | DATETIME | Default CURRENT_TIMESTAMP, Index | 登录时间 |
**索引**`idx_user_id`, `idx_ip`, `idx_status`, `idx_created_at`
**分区建议**MySQL/PostgreSQL按月分区保留最近 12 个月。
#### OperationLog操作日志
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGINT | PK, AutoIncrement | 日志唯一标识 |
| user_id | BIGINT | FK → users.id, Nullable, Index | 操作人 ID |
| action_type | VARCHAR(50) | Not Null | 操作类型(如 `user:create` |
| resource_type | VARCHAR(50) | Not Null, Index | 资源类型(如 `user`, `role` |
| resource_id | BIGINT | Nullable | 资源 ID |
| action | VARCHAR(20) | Not Null | 动作:`create` / `update` / `delete` |
| old_value | TEXT | Nullable | 操作前值JSON |
| new_value | TEXT | Nullable | 操作后值JSON |
| ip | VARCHAR(50) | Nullable | 操作 IP |
| user_agent | VARCHAR(500) | Nullable | User-Agent |
| created_at | DATETIME | Default CURRENT_TIMESTAMP, Index | 操作时间 |
**索引**`idx_user_id`, `idx_resource_type`, `idx_created_at`
**分区建议**MySQL/PostgreSQL按月分区保留最近 24 个月。
### 4.3 关联表
| 关联表 | 关联实体 | 说明 |
|--------|---------|------|
| `user_roles` | users ↔ roles | 多对多:用户角色分配 |
| `role_permissions` | roles ↔ permissions | 多对多:角色权限分配 |
| `user_social_accounts` | users | 一对多:第三方社交账号绑定 |
| `password_history` | users | 一对多:密码历史(防重用) |
| `webhooks` | - | Webhook 配置 |
| `webhook_deliveries` | webhooks | Webhook 投递日志 |
---
## 5. 接口设计RESTful API 分组列表)
基础路径:`/api/v1`
认证方式:`Authorization: Bearer <access_token>`
统一响应:`{ "code": 0, "message": "success", "data": {} }`
### 5.1 认证组Auth
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| POST | `/auth/register` | 公开 | 用户注册 |
| POST | `/auth/bootstrap-admin` | 公开 | 初始化管理员(首次启动) |
| POST | `/auth/login` | 公开 | 账号密码登录 |
| POST | `/auth/login/email-code` | 公开 | 邮箱验证码登录 |
| POST | `/auth/login/code` | 公开 | 短信验证码登录 |
| POST | `/auth/refresh` | 公开 | 刷新 Access TokenRefresh Token |
| POST | `/auth/logout` | 需认证 | 登出 |
| GET | `/auth/userinfo` | 需认证 | 获取当前用户信息 |
| GET | `/auth/capabilities` | 公开 | 获取系统能力配置 |
| GET | `/auth/activate` | 公开 | 邮箱激活 |
| POST | `/auth/resend-activation` | 公开 | 重发激活邮件 |
| POST | `/auth/forgot-password` | 公开 | 忘记密码 |
| GET | `/auth/reset-password` | 公开 | 验证重置 Token 页面 |
| POST | `/auth/reset-password` | 公开 | 提交新密码 |
| POST | `/auth/send-email-code` | 公开 | 发送邮箱验证码 |
| POST | `/auth/send-code` | 公开 | 发送短信验证码 |
| GET | `/auth/csrf-token` | 公开 | 获取 CSRF Token |
| GET | `/auth/captcha` | 公开 | 获取验证码配置 |
| GET | `/auth/captcha/image` | 公开 | 获取图形验证码 |
| POST | `/auth/captcha/verify` | 公开 | 验证图形验证码 |
### 5.2 双因素认证组2FA / TOTP
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| GET | `/auth/2fa/status` | 需认证 | 获取 2FA 状态 |
| GET | `/auth/2fa/setup` | 需认证 | 获取 TOTP 设置信息QR Code |
| POST | `/auth/2fa/enable` | 需认证 | 启用 TOTP |
| POST | `/auth/2fa/disable` | 需认证 | 禁用 TOTP |
| POST | `/auth/2fa/verify` | 需认证 | 验证 TOTP 码 |
### 5.3 OAuth2 组
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| GET | `/auth/oauth/providers` | 公开 | 获取已配置的 Provider 列表 |
| GET | `/auth/oauth/:provider` | 公开 | 跳转 OAuth2 授权页 |
| GET | `/auth/oauth/:provider/callback` | 公开 | OAuth2 回调处理 |
### 5.4 用户组User
| 方法 | 路径 | 认证/权限 | 说明 |
|------|------|----------|------|
| GET | `/users` | 管理员 | 用户列表(分页、筛选、排序) |
| GET | `/users/:id` | 本人或管理员 | 获取用户详情 |
| PUT | `/users/:id` | 本人或管理员 | 更新用户信息 |
| DELETE | `/users/:id` | `user:delete` | 删除用户 |
| PUT | `/users/:id/password` | 本人 | 修改密码 |
| PUT | `/users/:id/status` | `user:manage` | 修改用户状态 |
| GET | `/users/:id/roles` | 本人或管理员 | 获取用户角色 |
| PUT | `/users/:id/roles` | `user:manage` | 分配用户角色 |
| POST | `/users/:id/avatar` | 需认证 | 上传头像 |
| GET | `/users/me/social-accounts` | 需认证 | 获取当前用户社交账号 |
| POST | `/users/me/bind-social` | 需认证 | 绑定社交账号 |
| DELETE | `/users/me/bind-social/:provider` | 需认证 | 解绑社交账号 |
### 5.5 角色与权限组RBAC
| 方法 | 路径 | 认证/权限 | 说明 |
|------|------|----------|------|
| POST | `/roles` | 管理员 | 创建角色 |
| GET | `/roles` | 管理员 | 角色列表 |
| GET | `/roles/:id` | 管理员 | 角色详情 |
| PUT | `/roles/:id` | 管理员 | 更新角色 |
| DELETE | `/roles/:id` | 管理员 | 删除角色 |
| PUT | `/roles/:id/status` | 管理员 | 修改角色状态 |
| GET | `/roles/:id/permissions` | 管理员 | 获取角色权限 |
| PUT | `/roles/:id/permissions` | 管理员 | 分配角色权限 |
| POST | `/permissions` | 管理员 | 创建权限 |
| GET | `/permissions` | 管理员 | 权限列表 |
| GET | `/permissions/tree` | 管理员 | 权限树形结构 |
| GET | `/permissions/:id` | 管理员 | 权限详情 |
| PUT | `/permissions/:id` | 管理员 | 更新权限 |
| DELETE | `/permissions/:id` | 管理员 | 删除权限 |
| PUT | `/permissions/:id/status` | 管理员 | 修改权限状态 |
### 5.6 设备组Device
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| GET | `/devices` | 需认证 | 设备列表 |
| POST | `/devices` | 需认证 | 注册设备 |
| GET | `/devices/:id` | 需认证 | 设备详情 |
| PUT | `/devices/:id` | 需认证 | 更新设备 |
| DELETE | `/devices/:id` | 需认证 | 删除设备 |
| PUT | `/devices/:id/status` | 需认证 | 修改设备状态 |
| POST | `/devices/:id/trust` | 需认证 | 设置设备信任 |
| DELETE | `/devices/:id/trust` | 需认证 | 取消设备信任 |
| POST | `/devices/by-device-id/:deviceId/trust` | 需认证 | 按设备标识设置信任 |
| GET | `/devices/me/trusted` | 需认证 | 获取信任设备列表 |
| POST | `/devices/me/logout-others` | 需认证 | 登出所有其他设备 |
| GET | `/devices/users/:id` | 管理员 | 获取指定用户的设备 |
### 5.7 日志组Log
| 方法 | 路径 | 认证/权限 | 说明 |
|------|------|----------|------|
| GET | `/logs/login/me` | 需认证 | 当前用户登录日志 |
| GET | `/logs/operation/me` | 需认证 | 当前用户操作日志 |
| GET | `/logs/login` | 管理员 | 全量登录日志 |
| GET | `/logs/operation` | 管理员 | 全量操作日志 |
### 5.8 Webhook 组
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| POST | `/webhooks` | 需认证 | 创建 Webhook |
| GET | `/webhooks` | 需认证 | Webhook 列表 |
| PUT | `/webhooks/:id` | 需认证 | 更新 Webhook |
| DELETE | `/webhooks/:id` | 需认证 | 删除 Webhook |
| GET | `/webhooks/:id/deliveries` | 需认证 | 投递记录 |
### 5.9 管理员扩展组Admin
| 方法 | 路径 | 认证/权限 | 说明 |
|------|------|----------|------|
| GET | `/admin/users/export` | 管理员 | 导出用户CSV/XLSX |
| POST | `/admin/users/import` | 管理员 | 导入用户 |
| GET | `/admin/users/import/template` | 管理员 | 下载导入模板 |
| GET | `/admin/stats/dashboard` | 管理员 | 仪表盘统计 |
| GET | `/admin/stats/users` | 管理员 | 用户统计 |
### 5.10 基础设施端点
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| GET | `/health` | 公开 | 健康检查 |
| GET | `/health/live` | 公开 | Liveness Probe |
| GET | `/health/ready` | 公开 | Readiness Probe |
| GET | `/metrics` | 公开 | Prometheus 指标 |
| GET | `/swagger/*any` | 公开 | Swagger 文档 |
---
## 6. 安全设计
### 6.1 认证机制
| 机制 | 实现 | 说明 |
|------|------|------|
| **JWT 访问令牌** | RS256 非对称签名 | Access Token 有效期短(默认 2h携带用户 ID、角色、权限 |
| **Refresh Token** | 独立令牌,滚动轮换 | 每次刷新后旧 Refresh Token 失效,防重放 |
| **JTI 唯一标识** | timestamp(8B hex) + random(16B hex) | 防 Token 枚举,支持精确吊销 |
| **Token 黑名单** | Redis / 内存缓存 | 登出、密码修改后 Token 立即失效 |
| **密码修改失效PCE** | `password_changed_at` 字段 | 密码修改后旧 Token 自动失效 |
| **TOTP 双因素认证** | RFC 6238 | 6 位动态码,支持信任设备跳过 |
| **设备信任** | `is_trusted` + `trust_expires_at` | 信任设备在有效期内免 2FA |
| **OAuth2 第三方登录** | 标准 Authorization Code 流程 | 支持 GitHub、Google、微信等 Provider |
| **SSO 就绪** | JWT + 统一用户中心架构 | 可通过扩展支持单点登录 |
### 6.2 授权机制RBAC
| 机制 | 实现 | 说明 |
|------|------|------|
| **角色继承** | 自关联 `parent_id` + 层级 `level` | 子角色自动继承父角色权限,最大深度 20 |
| **权限代码** | `resource:action` 格式 | 如 `user:read`, `user:delete` |
| **权限类型** | `api` / `page` / `button` | 覆盖接口、页面、按钮三级权限 |
| **中间件鉴权** | `RequirePermission` / `RequireRole` | Handler 层统一拦截 |
| **数据级鉴权** | Service 层用户 ID 比对 | 如用户只能修改自己的资料 |
### 6.3 限流与防护
| 机制 | 实现 | 说明 |
|------|------|------|
| **接口限流** | 令牌桶算法 | 按 IP / 用户维度限流,防止暴力破解 |
| **限流内存清理** | 后台定期清理过期桶 | 防止内存泄漏 |
| **登录失败锁定** | 递增延迟 + 最大重试次数 | 防暴力破解 |
| **图形验证码** | 算术/字符验证码 | 注册、登录、重置密码前验证 |
| **CSRF 防护** | Double Submit Cookie + Token | POST/PUT/DELETE/PATCH 自动校验 |
| **CORS 白名单** | 配置化允许域名 | 拒绝危险通配符配置 |
| **IP 过滤** | 黑白名单机制 | 支持按 IP 段拦截 |
| **上传保护** | `/uploads` 路由认证中间件 | 防止未授权访问用户文件 |
### 6.4 密码策略
| 策略 | 实现 | 说明 |
|------|------|------|
| **哈希算法** | Argon2id | 内存硬函数,抗 GPU/ASIC 破解 |
| **自适应校准** | `auth.CalibrateArgon2id` | 启动时根据 CPU 自动调整参数 |
| **默认参数** | 64MB 内存3 次迭代4 并行度 | 平衡安全性与性能 |
| **密码历史** | `password_history` 表 | 禁止重用最近 N 次密码 |
| **历史异步保存** | goroutine + `context.WithTimeout` | 不阻塞主登录流程 |
| **常数时间比较** | `subtle.ConstantTimeCompare` | 防时序攻击 |
| **弱密码检测** | 常见弱密码字典 | 注册/修改时拦截 |
### 6.5 敏感数据保护
| 数据类型 | 保护措施 |
|---------|---------|
| **密码** | Argon2id 哈希,不可逆 |
| **TOTP Secret** | AES-256-GCM 加密存储 |
| **手机号/邮箱** | 日志中部分脱敏(如 `138****1234` |
| **Token** | 仅存储 JTI不存储完整 Token |
| **备份数据** | 加密存储,异地备份 |
| **传输层** | TLS 1.2+HSTS 头部 |
### 6.6 已修复安全漏洞(关键)
| 问题 | 严重等级 | 修复要点 |
|------|----------|----------|
| LIKE 查询 SQL 注入 | P0 | 参数化查询 + 转义 |
| 登录计数竞态条件 | P0 | 原子操作 / 分布式锁 |
| Refresh Token 黑名单 fail-open | P0 | 默认拒绝策略 |
| 验证码 Replay 攻击 | P0 | 一次性使用 + 过期校验 |
| CORS 危险配置 | P0 | 白名单校验 |
| UpdateUser IDOR 越权 | P0 | 数据级权限校验 |
| Login TOTP 绕过 | P0 | 验证流程强制化 |
| 游标分页数据错乱 | P0 | 稳定排序键 |
---
## 7. 性能优化清单
### 7.1 数据库优化
| 优化项 | 状态 | 说明 |
|--------|------|------|
| 批量查询替代循环查询(`FilterExistingUsernames` | **[已实施]** | `generateUniqueUsername` 使用批量 IN 查询替代逐条循环 |
| 单一查询替代串行查询(`FindByAccount` | **[已实施]** | `findUserForLogin` 使用一次查询覆盖 username/email/phone |
| 角色继承深度限制(`maxAncestorDepth=20` | **[已实施]** | 防止递归查询栈溢出与性能退化 |
| 数据库索引优化 | 已实施 | `users` 表 uk_username/uk_email/uk_phone/idx_status`login_logs` 按时间分区 |
| 预加载关联数据GORM Preload | 已实施 | 用户列表预加载角色,避免 N+1 |
| 游标分页替代 OFFSET | 已实施 | 大数据量列表使用 ID 游标分页 |
| 连接池调优 | 已实施 | `max_open_conns=100`, `max_idle_conns=20`, 连接生命周期 30min |
| 数据库读写分离 | 待实施 | 主库写、从库读,轮询负载均衡 |
### 7.2 缓存优化
| 优化项 | 状态 | 说明 |
|--------|------|------|
| L1 本地缓存 | 已实施 | 内存缓存用户、权限、Token 黑名单TTL 5min |
| L2 Redis 缓存 | 可选 | 分布式缓存TTL 30min支持集群 |
| 缓存穿透防护 | 已实施 | 空值缓存 + 布隆过滤器 |
| 缓存击穿防护 | 已实施 | SingleFlight 互斥锁,热点 Key 只回源一次 |
| 缓存雪崩防护 | 已实施 | 随机 TTL 抖动,避免集中过期 |
### 7.3 计算与并发优化
| 优化项 | 状态 | 说明 |
|--------|------|------|
| Argon2id 启动时自适应校准 | **[已实施]** | 根据当前 CPU 能力自动选择最优参数 |
| 密码历史异步保存 | **[已实施]** | goroutine + `context.WithTimeout` 不阻塞登录主流程 |
| RateLimiter 定期清理 | **[已实施]** | 后台定时清理过期限流桶,防止内存泄漏 |
| WorkerPool 协程池 | 已实施 | 批量操作限制并发度,防止 goroutine 爆炸 |
| 异步事件处理 | 已实施 | Webhook 投递、日志写入异步化 |
### 7.4 接口与路由优化
| 优化项 | 状态 | 说明 |
|--------|------|------|
| `/uploads` 路由认证保护 | **[已实施]** | 静态文件路由增加认证中间件 |
| Gzip 压缩 | 已实施 | 响应体 > 1KB 自动压缩 |
| HTTP/2 支持 | 已实施 | Nginx / Go 1.21+ 原生支持 |
| 静态资源 CDN | 待实施 | 生产环境头像、JS/CSS 走 CDN |
| 请求体大小限制 | 已实施 | 防止大文件 DOS |
### 7.5 性能目标
| 指标 | 目标值 | 说明 |
|------|--------|------|
| 并发用户数 | 100,000 | 集群部署 + Redis 会话 |
| QPS | 100,000 | 多级缓存 + 读写分离 |
| P50 响应时间 | < 100ms | 缓存命中场景 |
| P99 响应时间 | < 500ms | 含数据库回源 |
| 缓存命中率 | > 95% | L1 + L2 综合 |
---
## 8. 部署架构建议
### 8.1 单机部署SQLite + 可选 Redis
适用场景:开发测试、小型团队、单机低并发。
```
┌─────────────────────────────────────────┐
│ Nginx (反向代理) │
│ SSL 终止 / 静态资源缓存 │
└──────────────────┬──────────────────────┘
┌──────────────────▼──────────────────────┐
│ UMS 应用服务 (Go/Gin) │
│ ┌─────────────────────────────────┐ │
│ │ Handler / Service / Repository │ │
│ │ L1 本地缓存 (内存) │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ┌────────────────┼────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ SQLite │ │ Redis │ │ uploads│ │
│ │ (主存) │ │(可选L2)│ │ (受保护)│ │
│ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────┘
```
**配置要点**
- SQLite 文件存储在持久化卷
- 每日全量备份 SQLite 文件
- Redis 可选,用于分布式锁和二级缓存
- 单实例无状态,重启不影响数据
### 8.2 集群部署PostgreSQL + Redis Cluster
适用场景:生产环境、中大型应用、高可用要求。
```
┌─────────────────────────────────────────────────────────────┐
│ 全局负载均衡 (GSLB) │
│ DNS 轮询 / 健康检查 / 故障转移 │
└──────────────────────┬──────────────────────────────────────┘
┌──────────────┼──────────────┐
│ │ │
┌───────▼──────┐ ┌────▼──────┐ ┌─────▼──────┐
│ 机房 A │ │ 机房 B │ │ 机房 C │
│ (北京) │ │ (上海) │ │ (灾备) │
│ │ │ │ │ │
│ ┌──────────┐ │ │ ┌────────┐│ │ ┌────────┐ │
│ │ Nginx │ │ │ │ Nginx ││ │ │ Nginx │ │
│ │ 负载均衡 │ │ │ │负载均衡││ │ │负载均衡│ │
│ └────┬─────┘ │ │ └───┬────┘│ │ └───┬────┘ │
│ │ │ │ │ │ │ │ │
│ ┌────▼─────┐ │ │ ┌───▼───┐ │ │ ┌───▼───┐ │
│ │ UMS 集群 │ │ │ │UMS 集群│ │ │ │UMS 集群│ │
│ │ (多实例) │ │ │ │(多实例)│ │ │ │(多实例)│ │
│ │ L1 缓存 │ │ │ │L1 缓存 │ │ │ │L1 缓存 │ │
│ └────┬─────┘ │ │ └───┬───┘ │ │ └───┬───┘ │
│ │ │ │ │ │ │ │ │
│ ┌────▼─────┐ │ │ ┌───▼───┐ │ │ ┌───▼───┐ │
│ │Redis 集群│ │ │ │Redis │ │ │ │Redis │ │
│ │ 哨兵模式 │ │ │ │哨兵 │ │ │ │哨兵 │ │
│ └────┬─────┘ │ │ └───┬───┘ │ │ └───┬───┘ │
│ │ │ │ │ │ │ │ │
│ ┌────▼─────┐ │ │ ┌───▼───┐ │ │ ┌───▼───┐ │
│ │PG 主从 │ │ │ │PG 主从│ │ │ │PG 主从│ │
│ │ 主(写) │ │ │ │ 主(写)│ │ │ │ 主(写)│ │
│ │ 从(读)×2 │ │ │ │从(读)×2│ │ │ │从(读)×2│ │
│ └──────────┘ │ │ └───────┘ │ │ └───────┘ │
└──────────────┘ └───────────┘ └────────────┘
```
**配置要点**
- PostgreSQL 主从复制,从库承担读流量
- Redis 哨兵模式,高可用缓存与会话存储
- UMS 实例无状态,支持水平扩展
- Nginx 层做限流、SSL、静态缓存
- 跨机房异步复制RPO < 1min
### 8.3 容器化部署Docker Compose
```yaml
# docker-compose.yml 核心服务
services:
ums:
image: ums:latest
ports:
- "8080:8080"
environment:
- DATABASE_TYPE=postgres
- DATABASE_DSN=postgresql://ums:pass@postgres:5432/ums
- REDIS_ADDR=redis:6379
volumes:
- ./uploads:/app/uploads
depends_on:
- postgres
- redis
deploy:
replicas: 2
postgres:
image: postgres:15-alpine
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
```
### 8.4 Kubernetes 部署
| 资源 | 类型 | 说明 |
|------|------|------|
| **Deployment** | `ums-api` | 3+ 副本,滚动更新 |
| **Service** | `ClusterIP` + `LoadBalancer` | 内部集群 + 外部暴露 |
| **ConfigMap** | `ums-config` | 应用配置外置 |
| **Secret** | `ums-secrets` | JWT 私钥、数据库密码 |
| **HPA** | 自动扩缩容 | CPU > 70% 或 QPS 阈值触发 |
| **PVC** | `uploads-pvc` | 共享存储(或替换为 OSS |
| **Ingress** | Nginx Ingress | 路由、SSL、限流 |
| **PodDisruptionBudget** | `minAvailable: 2` | 保证升级时可用性 |
### 8.5 监控与告警
| 层级 | 组件 | 采集指标 |
|------|------|----------|
| 基础设施 | Node Exporter | CPU、内存、磁盘、网络 |
| 中间件 | Redis Exporter / Postgres Exporter | 连接数、QPS、慢查询 |
| 应用 | Prometheus + OpenTelemetry | HTTP 延迟、错误率、缓存命中率 |
| 日志 | Grafana Loki / ELK | 结构化日志检索 |
| 告警 | Prometheus Alertmanager | P99 > 500ms、错误率 > 1%、磁盘 > 80% |
---
## 附录:文档索引
| 文档 | 路径 | 说明 |
|------|------|------|
| API 契约 | `docs/API.md` | 完整接口定义与响应示例 |
| 数据模型 | `docs/DATA_MODEL.md` | 数据库表结构、索引、ER 图 |
| 技术架构 | `docs/ARCHITECTURE.md` | 性能优化、缓存策略、监控 |
| 部署指南 | `docs/DEPLOYMENT.md` | 环境配置、升级、回滚 |
| 安全文档 | `docs/SECURITY.md` | 安全机制、漏洞修复记录 |
| PRD | `docs/PRD.md` | 产品需求文档 |
---
*本文档持续更新,如有变更请同步更新本文件及相关子文档。*