Files
user-system/docs/architecture-design.md

827 lines
44 KiB
Markdown
Raw Normal View History

# 用户管理系统架构设计文档
> 版本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` | 产品需求文档 |
---
*本文档持续更新,如有变更请同步更新本文件及相关子文档。*