refactor: 整理项目根目录结构
整理内容: - 删除 60+ 临时测试输出文件 (*.txt) - 移动二进制文件到 bin/ 目录 - 移动 Shell 脚本到 scripts/ 目录 - scripts/dev/: check_gitea.sh, check_sub2api.sh, run_tests.sh - scripts/deploy/: deploy_*.sh, simple_deploy.sh - scripts/ops/: fix_nginx.sh, fix_ssl.sh, install_docker.sh - scripts/test/: test_*.sh, test_*.bat - 移动批处理文件到 scripts/ - 移动 Python 脚本到 tools/ - 清理临时日志文件 保留根目录必要文件: - go.mod, go.sum, go.work - Makefile, docker-compose.yml - .env.example, .gitignore - README.md, AGENTS.md, DEPLOY_GUIDE.md 验证: go build ./... && go test ./... 通过
This commit is contained in:
296
docs/code-review/COMPREHENSIVE_REVIEW_2026-04-02.md
Normal file
296
docs/code-review/COMPREHENSIVE_REVIEW_2026-04-02.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# 全面系统性审查报告
|
||||
|
||||
**审查日期**: 2026-04-02
|
||||
**审查范围**: 后端 Go + 前端 React/TypeScript + PRD 对齐 + API 文档 + E2E 测试 + 安全
|
||||
**审查方法**: 多智能体并行审查(后端审查、前端审查、PRD 缺口分析、API 文档审查)
|
||||
|
||||
---
|
||||
|
||||
## 一、执行摘要
|
||||
|
||||
### 综合评分
|
||||
|
||||
| 维度 | 得分 | 说明 |
|
||||
|------|------|------|
|
||||
| 后端代码质量 | 7.5/10 | 架构清晰,安全基础扎实,但存在 1 个严重问题和 8 个重要问题 |
|
||||
| 前端代码质量 | 7.0/10 | 安全设计良好(内存 Token、window guard),但存在 4 个严重问题和 22 个重要问题 |
|
||||
| 功能完整度 | 8.5/10 | 核心功能完整,主要缺口在前端缺失页面和批量操作 |
|
||||
| E2E 覆盖度 | 6.0/10 | 15 个场景覆盖主流程,但多为"页面存在"级验证 |
|
||||
| API 文档准确度 | 4.0/10 | 遗漏 38 个端点,文档需大幅更新 |
|
||||
| **综合评分** | **6.6/10** | 核心链路可用,但距离"可诚实宣称全面收口"还有明显差距 |
|
||||
|
||||
### 问题统计
|
||||
|
||||
| 严重级别 | 后端 | 前端 | 总计 |
|
||||
|----------|------|------|------|
|
||||
| 🔴 严重 | 1 | 4 | 5 |
|
||||
| 🟡 重要 | 8 | 22 | 30 |
|
||||
| 💭 轻微 | 12 | 8 | 20 |
|
||||
| **总计** | **21** | **34** | **55** |
|
||||
|
||||
---
|
||||
|
||||
## 二、后端审查结果
|
||||
|
||||
### 2.1 🔴 严重问题(1 个)
|
||||
|
||||
| ID | 文件 | 问题 | 影响 |
|
||||
|----|------|------|------|
|
||||
| SEC-NEW-01 | `internal/auth/sso.go` | SSO 会话存储在无界内存 map,无清理机制 | 内存泄漏、重启丢失所有 SSO 会话、DoS 风险 |
|
||||
|
||||
### 2.2 🟡 重要问题(8 个)
|
||||
|
||||
| ID | 文件 | 问题 |
|
||||
|----|------|------|
|
||||
| PERF-01 | `internal/api/middleware/ratelimit.go` | SlidingWindowLimiter cleanupInt 死代码 |
|
||||
| SEC-02 | `internal/api/middleware/auth.go` | isJTIBlacklisted 使用 context.Background() |
|
||||
| SEC-03 | `internal/service/auth.go` | 登录日志 goroutine 无生命周期管理 |
|
||||
| SEC-04 | `internal/service/webhook.go` | Webhook deliver() 使用 context.Background() |
|
||||
| CORR-01 | `internal/api/handler/auth_handler.go` | handleError 返回原始错误信息给客户端 |
|
||||
| CORR-02 | `internal/api/handler/sso_handler.go` | SSO handler 未检查类型断言(panic 风险) |
|
||||
| PERF-02 | `internal/service/stats.go` | GetUserStats 5+ 次独立 DB 查询(N+5 模式) |
|
||||
| SEC-05 | `internal/service/sms.go` | 短信验证码使用非恒定时间比较 |
|
||||
|
||||
### 2.3 历史问题修复状态
|
||||
|
||||
| 问题 | 状态 |
|
||||
|------|------|
|
||||
| OAuth ValidateToken 始终返回 true | ✅ 已修复 |
|
||||
| JTI 含可预测时间戳 | ✅ 已修复 |
|
||||
| TOTP 使用 SHA1 | ✅ 已修复 → SHA256 |
|
||||
| Refresh 接口无限流 | ✅ 已修复 |
|
||||
| Webhook SSRF 风险 | ✅ 已修复 |
|
||||
| Webhook context.Background() | ⚠️ 部分修复(有超时但仍用 Background) |
|
||||
| 邮件 goroutine context 问题 | ❌ 未修复 |
|
||||
| SlidingWindowLimiter 清理死代码 | ❌ 未修复 |
|
||||
| stats N+5 查询 | ❌ 未修复 |
|
||||
|
||||
---
|
||||
|
||||
## 三、前端审查结果
|
||||
|
||||
### 3.1 🔴 严重问题(4 个)
|
||||
|
||||
| ID | 文件 | 问题 | 影响 |
|
||||
|----|------|------|------|
|
||||
| C01 | `LoginPage.tsx:76-79` | 设备指纹存储在 localStorage | XSS 可读取设备追踪信息 |
|
||||
| C02 | `ProfileSecurityPage.tsx:308-314` | TOTP 流程从 localStorage 读取设备指纹 | XSS 可注入恶意设备指纹 |
|
||||
| C03 | `client.ts:210-221` | Token 刷新重试可能重复执行非幂等请求 | 可能导致重复创建用户等操作 |
|
||||
| C04 | `oauth.ts:3` | Open redirect 验证不充分 | 可能被利用进行开放重定向攻击 |
|
||||
|
||||
### 3.2 🟡 重要问题(22 个)
|
||||
|
||||
主要类别:
|
||||
- **性能**: 所有管理页面的 table columns 在组件体内定义(6 个页面)
|
||||
- **代码重复**: triggerFileDownload 在 2 个文件中重复,resolveApiBaseUrl 在 2 个文件中重复
|
||||
- **组件拆分**: ProfileSecurityPage 946 行、30+ 状态变量,需要拆分为子组件
|
||||
- **类型安全**: UserEditDrawer、RoleFormModal 的 Form.useForm() 缺少类型参数
|
||||
- **构建配置**: vite.config.js 无代码分割配置
|
||||
- **静态数据**: SettingsPage 使用硬编码静态数据
|
||||
|
||||
---
|
||||
|
||||
## 四、PRD 缺口分析
|
||||
|
||||
### 4.1 功能实现状态
|
||||
|
||||
| 功能模块 | 状态 | 说明 |
|
||||
|----------|------|------|
|
||||
| 邮箱注册 + 激活 | ✅ | 完整实现,E2E 覆盖 |
|
||||
| 手机号注册 | ✅ | 完整实现 |
|
||||
| 社交账号登录(9 平台) | ✅ | 完整实现 |
|
||||
| TOTP 双因素认证 | ✅ | 完整实现,SHA256 |
|
||||
| 密码重置(邮箱/短信) | ✅ | 完整实现 |
|
||||
| RBAC 权限管理 | ✅ | 角色继承已修复 |
|
||||
| 用户管理 CRUD | ✅ | E2E 覆盖 |
|
||||
| 设备信任管理 | ⚠️ | API 完整,登录流程信任检查已接入 |
|
||||
| 异地登录检测 | ⚠️ | AnomalyDetector 已注入,缺 GeoIP |
|
||||
| 批量操作 | ❌ | 前端无批量操作 UI |
|
||||
| 管理员管理页 | ❌ | 后端 API 存在,前端页缺失 |
|
||||
| 系统设置页 | ❌ | 前端页缺失 |
|
||||
| 全局设备管理页 | ❌ | 后端 API 存在,前端页缺失 |
|
||||
| CAS/SAML SSO | ❌ | PRD 标注可选,建议 v2.0 |
|
||||
| SDK(Java/Go/Rust) | ❌ | 未实现,建议 v2.0 |
|
||||
| 防重放攻击 | ❌ | Nonce 机制未实现 |
|
||||
|
||||
### 4.2 关键缺口
|
||||
|
||||
1. **前端缺失页面**(3 个):管理员管理页、系统设置页、全局设备管理页
|
||||
2. **批量操作 UI**:用户/角色批量删除、批量分配角色
|
||||
3. **防重放攻击**:Nonce 机制未实现
|
||||
|
||||
---
|
||||
|
||||
## 五、API 文档审查
|
||||
|
||||
### 5.1 文档缺口统计
|
||||
|
||||
- **代码有但文档无**: 38 个端点
|
||||
- **文档有但代码无**: 0 个
|
||||
- **描述需补充**: 2 个端点
|
||||
|
||||
### 5.2 未记录端点分类
|
||||
|
||||
| 类别 | 数量 | 端点 |
|
||||
|------|------|------|
|
||||
| 自定义字段管理 | 7 | `/custom-fields` CRUD + `/users/me/custom-fields` |
|
||||
| 主题管理 | 7 | `/themes` CRUD + `/theme/active` + default |
|
||||
| SSO | 5 | `/sso/authorize`, `/sso/token`, `/sso/introspect`, `/sso/revoke`, `/sso/userinfo` |
|
||||
| 管理员设备管理 | 5 | `/admin/devices` CRUD + trust |
|
||||
| 邮箱/手机绑定 | 6 | `/users/me/bind-email/*`, `/users/me/bind-phone/*` |
|
||||
| 其他 | 8 | OAuth exchange, 短信密码重置, 登录日志导出, 管理员 CRUD |
|
||||
|
||||
### 5.3 建议
|
||||
|
||||
- 使用脚本从 `router.go` 自动生成 API 文档骨架
|
||||
- 补充请求/响应示例
|
||||
- 更新权限说明
|
||||
|
||||
---
|
||||
|
||||
## 六、E2E 测试审查
|
||||
|
||||
### 6.1 当前覆盖场景(15 个)
|
||||
|
||||
| # | 场景 | 覆盖深度 | 说明 |
|
||||
|---|------|----------|------|
|
||||
| 1 | admin-bootstrap | 🔵 深度 | 完整引导 → 登录 → 登出流程 |
|
||||
| 2 | public-registration | 🔵 深度 | 注册 → 登录 → 登出流程 |
|
||||
| 3 | email-activation | 🔵 深度 | 注册 → 收取邮件 → 激活 → 登录 → 登出 |
|
||||
| 4 | login-surface | 🔵 深度 | 登录页 UI、capabilities、未登录重定向 |
|
||||
| 5 | auth-workflow | 🔵 深度 | 登录 → 用户详情 → 角色分配 → 创建用户 → 登出 |
|
||||
| 6 | responsive-login | 🔵 深度 | 三视口登录页验证 |
|
||||
| 7 | desktop-mobile-navigation | 🔵 深度 | 桌面导航 + 移动端抽屉菜单 |
|
||||
| 8 | user-management-crud | 🔵 深度 | 创建 → 编辑 → 详情 → 筛选 → 删除 |
|
||||
| 9 | role-management-crud | 🟡 中等 | 角色列表 + 权限分配弹窗 |
|
||||
| 10 | device-management | 🟡 中等 | 页面导航 + 列表显示 |
|
||||
| 11 | login-logs | 🟡 中等 | 页面导航 + 列表显示 |
|
||||
| 12 | operation-logs | 🟡 中等 | 页面导航 + 列表显示 |
|
||||
| 13 | webhook-management | 🟡 中等 | 页面导航 + 列表显示 |
|
||||
| 14 | profile-and-security | 🟡 中等 | 个人资料 + 安全设置可见性 |
|
||||
| 15 | dashboard-stats | 🟡 中等 | 仪表盘统计卡片验证 |
|
||||
|
||||
### 6.2 E2E 缺口
|
||||
|
||||
| 缺口 | 优先级 | 说明 |
|
||||
|------|--------|------|
|
||||
| 忘记密码流程(邮箱/短信) | 🔴 | PRD 核心流程,无 E2E 覆盖 |
|
||||
| TOTP 启用/禁用完整流程 | 🟡 | 只验证可见,未验证交互 |
|
||||
| 社交账号绑定/解绑 | 🟡 | 无 E2E 覆盖 |
|
||||
| 角色创建/编辑/删除 | 🟡 | 只验证列表,未验证 CRUD |
|
||||
| 权限 CRUD | 🟡 | 无 E2E 覆盖 |
|
||||
| Webhook 创建/编辑/删除 | 🟡 | 只验证页面存在 |
|
||||
| 用户导入/导出 | 🟡 | 无 E2E 覆盖 |
|
||||
| 设备信任/取消信任 | 🟡 | 只验证页面存在 |
|
||||
| 后台页面响应式 | 🟡 | 仅登录页做响应式验证 |
|
||||
|
||||
### 6.3 防虚假测试检查
|
||||
|
||||
✅ **通过项**:
|
||||
- 所有 E2E 测试启动真实后端进程(隔离测试数据库)
|
||||
- 所有 E2E 测试启动真实前端开发服务器
|
||||
- 所有 E2E 测试通过真实浏览器(CDP 协议)执行用户操作
|
||||
- 所有 E2E 测试验证真实 API 响应(非 mock)
|
||||
- 本地 SMTP 捕获服务验证邮件发送
|
||||
- 信号收集器监控 console errors、dialogs、popups、request failures、401 responses
|
||||
|
||||
---
|
||||
|
||||
## 七、安全审查
|
||||
|
||||
### 7.1 安全优势
|
||||
|
||||
- ✅ 密码使用 Argon2id 哈希
|
||||
- ✅ 敏感数据使用 crypto/rand 生成
|
||||
- ✅ Webhook URL 有 SSRF 保护
|
||||
- ✅ 接口限流已配置(含 refresh 接口)
|
||||
- ✅ Access Token 仅存储在内存中
|
||||
- ✅ 前端安装 window guard 阻断 alert/confirm/prompt/open
|
||||
- ✅ CSRF Token 支持
|
||||
- ✅ JWT JTI 黑名单机制
|
||||
|
||||
### 7.2 安全风险
|
||||
|
||||
| 风险 | 严重级别 | 说明 |
|
||||
|------|----------|------|
|
||||
| SSO 会话内存泄漏 | 🔴 | 无界 map 无清理 |
|
||||
| 设备指纹 localStorage | 🔴 | XSS 可读取/注入 |
|
||||
| Open redirect 验证不足 | 🔴 | 可能被利用 |
|
||||
| 非恒定时间比较 | 🟡 | SMS/邮箱验证码 |
|
||||
| 错误信息泄露 | 🟡 | 返回原始错误给客户端 |
|
||||
| context.Background() 滥用 | 🟡 | 5 处使用 |
|
||||
|
||||
---
|
||||
|
||||
## 八、优先级建议
|
||||
|
||||
### P0:必须立即修复
|
||||
|
||||
1. **SEC-NEW-01**: SSO 会话 map 添加清理机制或持久化
|
||||
2. **C01/C02**: 移除设备指纹的 localStorage 存储
|
||||
3. **C04**: 修复 OAuth open redirect 验证
|
||||
4. **API.md**: 补充 38 个未记录端点
|
||||
|
||||
### P1:应在当前迭代解决
|
||||
|
||||
5. **SEC-02/03/04**: 修复 context.Background() 滥用(5 处)
|
||||
6. **SEC-05**: SMS/邮箱验证码使用恒定时间比较
|
||||
7. **CORR-01**: 错误信息分类,不返回原始错误给客户端
|
||||
8. **CORR-02**: SSO handler 类型断言安全检查
|
||||
9. **前端**: 所有管理页面 table columns 使用 useMemo
|
||||
10. **前端**: ProfileSecurityPage 拆分为子组件
|
||||
11. **E2E**: 补充忘记密码流程测试
|
||||
|
||||
### P2:下一轮持续优化
|
||||
|
||||
12. **PERF-02**: stats.go 合并为单次 GROUP BY 查询
|
||||
13. **前端**: 提取重复代码(triggerFileDownload、resolveApiBaseUrl)
|
||||
14. **前端**: vite.config.js 添加代码分割配置
|
||||
15. **前端**: 补齐缺失的服务层测试
|
||||
16. **E2E**: 深化现有场景的交互验证深度
|
||||
17. **前端**: 补齐缺失页面(管理员管理、系统设置、全局设备管理)
|
||||
18. **安全**: 实现防重放攻击 Nonce 机制
|
||||
|
||||
---
|
||||
|
||||
## 九、当前项目真实状态
|
||||
|
||||
### 可以说
|
||||
|
||||
- 后端核心功能完整,go vet/build/test 全绿
|
||||
- 前端主后台已成型,15 个页面已实现
|
||||
- 浏览器级真实 E2E 已覆盖 15 个场景
|
||||
- 代码架构清晰(handler → service → repository,service → API → component)
|
||||
- 安全基础扎实(Argon2id、crypto/rand、SSRF 保护、window guard)
|
||||
|
||||
### 不可以说
|
||||
|
||||
- "全部功能已闭环"(前端缺 3 个页面 + 批量操作)
|
||||
- "E2E 测试已充分"(15 个场景多为页面存在级验证)
|
||||
- "API 文档已完整"(遗漏 38 个端点)
|
||||
- "无安全风险"(1 个严重 + 4 个严重前端问题待修复)
|
||||
|
||||
### 最诚实的表述
|
||||
|
||||
> **后端能力比较完整,前端主后台已经成型,代码质量总体在可控范围内,但"自动化验证闭环"和"PRD 最后一公里"还没有完全收口。**
|
||||
>
|
||||
> 如果只看代码实现度,项目已经不低;如果按"可审计、可重复、可对外诚实宣称"的标准看,当前还差最后几步:
|
||||
> - 修复 5 个严重安全问题
|
||||
> - 补齐 3 个前端缺失页面
|
||||
> - 深化 E2E 测试覆盖深度
|
||||
> - 同步 API 文档
|
||||
|
||||
---
|
||||
|
||||
## 十、审查方法说明
|
||||
|
||||
本次审查采用多智能体并行模式:
|
||||
- **后端审查智能体**: 审查所有 Go 代码(安全、性能、错误处理、架构)
|
||||
- **前端审查智能体**: 审查所有 React/TypeScript 代码(安全、类型、性能、测试)
|
||||
- **PRD 缺口分析智能体**: 对比 PRD 与实际实现,识别缺口
|
||||
- **API 文档审查智能体**: 对比 API.md 与 router.go,识别文档缺口
|
||||
|
||||
审查覆盖:
|
||||
- 后端: 30+ Go 文件(internal/api、service、repository、middleware、auth、config、database、cmd)
|
||||
- 前端: 50+ TypeScript/TSX 文件(pages、components、services、lib、app)
|
||||
- 文档: PRD、API.md、历史审查报告、项目状态文档
|
||||
128
docs/code-review/COMPREHENSIVE_SECURITY_REVIEW_2026-04-03.md
Normal file
128
docs/code-review/COMPREHENSIVE_SECURITY_REVIEW_2026-04-03.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# 生产级全面审查报告 - 2026-04-03
|
||||
|
||||
**审查范围**: Go 后端 + React/TypeScript 前端 + 架构设计
|
||||
**审查方法**: 多智能体深度审查 (并发/安全/前端/架构)
|
||||
|
||||
---
|
||||
|
||||
## 执行摘要
|
||||
|
||||
| 维度 | 得分 | 严重问题 |
|
||||
|------|------|----------|
|
||||
| 后端安全 | 5/10 | CRITICAL x2, HIGH x6 |
|
||||
| 前端安全 | 8/10 | MEDIUM x1 |
|
||||
| 并发生命周期 | 8/10 | LOW x2 |
|
||||
| 架构设计 | 7/10 | MEDIUM x2 |
|
||||
| **综合** | **6.5/10** | 共 27 个问题 |
|
||||
|
||||
---
|
||||
|
||||
## 🔴 CRITICAL 问题 (2个)
|
||||
|
||||
### 1. BootstrapAdmin 端点无认证保护
|
||||
- **文件**: `router.go:116`
|
||||
- **问题**: `/auth/bootstrap-admin` 仅限流,无认证中间件
|
||||
- **影响**: 攻击者可创建初始管理员账号
|
||||
|
||||
### 2. 错误信息泄露给客户端
|
||||
- **文件**: `auth_handler.go:381`
|
||||
- **问题**: `handleError` 返回原始 `err.Error()` 给客户端
|
||||
- **影响**: 数据库错误、文件路径等内部信息泄露
|
||||
|
||||
---
|
||||
|
||||
## 🟠 HIGH 问题 (6个)
|
||||
|
||||
### 3. 主题 CustomCSS/CustomJS 存储型 XSS
|
||||
- **文件**: `theme_handler.go`
|
||||
- **影响**: 管理员可注入恶意 JS 到所有用户页面
|
||||
|
||||
### 4. GetUserDevices IDOR 漏洞
|
||||
- **文件**: `device_handler.go:159`
|
||||
- **影响**: 任何用户可查询其他用户的设备列表
|
||||
|
||||
### 5. TOTP 恢复码非恒定时间比较
|
||||
- **文件**: `totp.go`
|
||||
- **影响**: 时序攻击可逐步暴破恢复码
|
||||
|
||||
### 6. 短信/邮件验证码非恒定时间比较
|
||||
- **文件**: `sms.go:360`, `email.go:170`
|
||||
- **影响**: 时序攻击可逐步暴破验证码
|
||||
|
||||
### 7. 缓存一致性问题 (用户数据变更不清除缓存)
|
||||
- **文件**: `user_service.go`
|
||||
- **影响**: 密码修改后 15 分钟内缓存用户信息仍为旧数据
|
||||
|
||||
### 8. Redis 失败时安全路径静默失败
|
||||
- **影响**: 登录计数/令牌黑名单在 Redis 错误时静默失败
|
||||
|
||||
---
|
||||
|
||||
## 🟡 MEDIUM 问题 (12个)
|
||||
|
||||
| # | 问题 | 文件 |
|
||||
|---|------|------|
|
||||
| 9 | CORS 通配符 + AllowCredentials | cors.go |
|
||||
| 10 | OAuth implicit flow token 暴露在 URL | sso_handler.go |
|
||||
| 11 | 内存限流可被重启绕过 | ratelimit.go |
|
||||
| 12 | CAS XML 解析用字符串操作 | cas.go |
|
||||
| 13 | SanitizeXSS 自毁式还原 | validator.go |
|
||||
| 14 | 桩端点返回 200 而非 501 | auth_handler.go |
|
||||
| 15 | 操作日志超时太短 (3s) | operation_log.go |
|
||||
| 16 | StateManager 清理未启动 (死代码) | state.go |
|
||||
| 17 | SSO IntrospectToken 锁升级竞态 | sso.go |
|
||||
| 18 | Webhook 重试任务关闭时丢失 | webhook.go |
|
||||
| 19 | 密码策略默认太弱 | auth.go |
|
||||
| 20 | 邮箱验证码分布不均匀 | email.go |
|
||||
|
||||
---
|
||||
|
||||
## 🟢 LOW/INFO 问题 (7个)
|
||||
|
||||
| # | 问题 | 严重度 |
|
||||
|---|------|--------|
|
||||
| 21 | 密码策略默认太弱 | LOW |
|
||||
| 22 | 邮箱验证码非均匀分布 | LOW |
|
||||
| 23 | Regex 未预编译 | LOW |
|
||||
| 24 | RSA 密钥 2048 位 | LOW |
|
||||
| 25 | SSO 内存会话无持久化 | INFO |
|
||||
| 26 | JWT 黑名单 TTL 受限于令牌剩余寿命 | INFO |
|
||||
| 27 | Webhook SSRF DNS 重绑定风险 | INFO |
|
||||
|
||||
---
|
||||
|
||||
## ✅ 正面安全实践
|
||||
|
||||
1. **Argon2id 密码哈希** - 64MB 内存,5 次迭代
|
||||
2. **参数化查询** - 所有 Repository 使用 GORM 参数化
|
||||
3. **LIKE 注入防护** - `escapeLikePattern()` 正确使用
|
||||
4. **Webhook SSRF 防护** - `isSafeURL()` 阻止内网地址
|
||||
5. **HMAC 签名** - Webhook 载荷使用 HMAC-SHA256
|
||||
6. **RBAC 中间件** - 细粒度权限检查
|
||||
7. **限流** - 内存 + Redis 双限流实现
|
||||
8. **登录异常检测** - 暴力破解/新位置/新设备检测
|
||||
9. **设备信任机制** - 用户可审查和撤销信任设备
|
||||
10. **恢复码 Argon2id 哈希** - 存储前哈希
|
||||
|
||||
---
|
||||
|
||||
## 修复优先级
|
||||
|
||||
| 优先级 | 问题 | 工作量 |
|
||||
|--------|------|--------|
|
||||
| P0 | BootstrapAdmin 认证 + 错误信息泄露 | 小 |
|
||||
| P1 | IDOR + 存储型 XSS + 时序攻击 | 中 |
|
||||
| P2 | 缓存一致性 + Redis 静默失败 | 中 |
|
||||
| P3 | 其他 MEDIUM/LOW 问题 | 大 |
|
||||
|
||||
---
|
||||
|
||||
## 验证矩阵
|
||||
|
||||
```
|
||||
go build ./... ✅
|
||||
go test ./... ✅
|
||||
go vet ./... ✅
|
||||
npm run build ✅
|
||||
npm run lint ✅
|
||||
```
|
||||
288
docs/code-review/CONSISTENCY_PERFORMANCE_REVIEW_2026-04-02.md
Normal file
288
docs/code-review/CONSISTENCY_PERFORMANCE_REVIEW_2026-04-02.md
Normal file
@@ -0,0 +1,288 @@
|
||||
# 前后端一致性 + 架构性能专项审查报告
|
||||
|
||||
**审查日期**: 2026-04-02
|
||||
**审查范围**: 前后端一致性 + 架构性能执行
|
||||
**审查方法**: 多智能体并行审查(一致性审查、性能审查)
|
||||
|
||||
---
|
||||
|
||||
## 一、执行摘要
|
||||
|
||||
### 综合评分
|
||||
|
||||
| 维度 | 得分 | 说明 |
|
||||
|------|------|------|
|
||||
| 前后端一致性 | 2.0/10 | 存在根本性协议层不匹配,72 个端点路由正确但请求/响应格式全面错位 |
|
||||
| 架构性能执行 | 5.5/10 | 架构基础合理,但 SQLite、N+1 查询、无界导出等严重制约扩展性 |
|
||||
| **综合评分** | **3.8/10** | 这是当前项目最薄弱的两个环节,必须优先修复 |
|
||||
|
||||
### 问题统计
|
||||
|
||||
| 严重级别 | 一致性 | 性能 | 总计 |
|
||||
|----------|--------|------|------|
|
||||
| 🔴 严重 | 18 | 7 | 25 |
|
||||
| 🟡 重要 | 14 | 17 | 31 |
|
||||
| 💭 轻微 | 8 | 8 | 16 |
|
||||
| **总计** | **40** | **32** | **72** |
|
||||
|
||||
---
|
||||
|
||||
## 二、前后端一致性审查
|
||||
|
||||
### 2.1 根本性问题:响应格式协议不匹配
|
||||
|
||||
**这是整个项目最严重的一致性问题。**
|
||||
|
||||
- **前端期望**: 所有 API 响应格式为 `{code: number, data: T, message: string}`
|
||||
- **后端实际**: 直接返回裸 JSON,如 `{users: [...], total: 100}` 或 `{error: "..."}`
|
||||
- **影响**: 前端 `client.ts` 检查 `result.code !== 0` 时,`result.code` 为 `undefined`,导致**每个 API 调用都会抛出错误**。
|
||||
- **结论**: 如果这不是在隔离测试环境中运行(测试环境可能走了不同的代码路径),整个应用将无法正常工作。
|
||||
|
||||
### 2.2 一致性问题分类
|
||||
|
||||
#### 🔴 严重问题(18 个)
|
||||
|
||||
| ID | 类别 | 前端 | 后端 | 问题 |
|
||||
|----|------|------|------|------|
|
||||
| CONSISTENCY-01 | 全局 | `client.ts:240-245` | ALL handlers | 响应格式不匹配:前端期望 `{code, data, message}`,后端返回裸 JSON |
|
||||
| CONSISTENCY-02 | 用户列表 | `users.ts:23-24` | `user_handler.go:76-81` | 响应 key: `items` vs `users`,分页: `page/page_size` vs `offset/limit` |
|
||||
| CONSISTENCY-03 | 角色列表 | `roles.ts:11-15` | `role_handler.go:52-55` | 响应 key: `items` vs `roles`,缺 `page/page_size` |
|
||||
| CONSISTENCY-04 | 角色权限 | `roles.ts:38-40` | `role_handler.go:160` | 前端期望数组,后端返回 `{permissions: [...]}` |
|
||||
| CONSISTENCY-05 | 权限列表 | `permissions.ts:22-23` | `permission_handler.go:52-55` | 前端期望数组,后端返回 `{permissions, total}` |
|
||||
| CONSISTENCY-06 | 权限树 | `permissions.ts:14-15` | `permission_handler.go:153` | 前端期望数组,后端返回 `{permissions: tree}` |
|
||||
| CONSISTENCY-07 | 设备列表 | `devices.ts:10-14` | `device_handler.go:63-68` | 响应 key: `items` vs `devices` |
|
||||
| CONSISTENCY-08 | 管理员设备 | `devices.ts:18-22` | `device_handler.go:198-203` | 响应 key: `items` vs `devices` |
|
||||
| CONSISTENCY-09 | Webhook 列表 | `webhooks.ts:35-47` | `webhook_handler.go:26` | 响应 key: `data` vs `webhooks` |
|
||||
| CONSISTENCY-10 | 登录日志 | `login-logs.ts:12-22` | `log_handler.go:43-48` | 响应 key: `list` vs `logs`,`size` vs `page_size` |
|
||||
| CONSISTENCY-11 | 操作日志 | `operation-logs.ts:12-22` | `log_handler.go:52` | 响应 key: `list` vs `logs` |
|
||||
| CONSISTENCY-12 | 下线设备 | `devices.ts:58-59` | `device_handler.go:308-314` | 前端发送 body `current_device_id`,后端读 header `X-Device-ID` |
|
||||
| CONSISTENCY-13 | 修改密码 | `profile.ts:52-53` | `user_handler.go:160-162` | 前端发送 `current_password`,后端期望 `old_password` |
|
||||
| CONSISTENCY-14 | TOTP 状态 | `auth.ts:129-130` | `totp_handler.go:38` | 前端期望 `totp_enabled`,后端返回 `enabled` |
|
||||
| CONSISTENCY-15 | Capabilities | `auth.ts:34-36` | `auth_handler.go:136-141` | 字段完全错位:前端期望 `password/email_activation/...`,后端返回 `register/login/...` |
|
||||
| CONSISTENCY-16 | Bootstrap | `types/auth.ts:80-84` | `auth_handler.go:243-247` | 前端 `email` 可选,后端必填;前端发 `nickname`,后端不收 |
|
||||
| CONSISTENCY-17 | 注册 | `types/auth.ts:71-78` | `auth_handler.go:22-28` | 前端发 `phone_code`,后端不收 |
|
||||
| CONSISTENCY-18 | 重置密码 | `types/auth.ts:114-118` | `password_reset_handler.go:65-68` | 前端发 `confirm_password`,后端不收 |
|
||||
|
||||
#### 🟡 重要问题(14 个)
|
||||
|
||||
| ID | 类别 | 问题 |
|
||||
|----|------|------|
|
||||
| CONSISTENCY-19 | 用户状态 | 前端发送数字 `0|1|2|3`,后端期望字符串 `"active"/"inactive"/...` |
|
||||
| CONSISTENCY-20 | 角色状态 | 前端发送数字 `0|1`,后端期望字符串 `"enabled"/"disabled"` |
|
||||
| CONSISTENCY-21 | 权限状态 | 前端发送数字 `0|1`,后端期望字符串 `"enabled"/"disabled"` |
|
||||
| CONSISTENCY-22 | 设备状态 | 前端发送数字 `0|1`,后端期望字符串 `"active"/"inactive"` |
|
||||
| CONSISTENCY-23 | 分页参数 | 前端发送 `page/page_size`,后端读取 `offset/limit` |
|
||||
| CONSISTENCY-24 | 用户更新 | 前端发 7 个字段,后端只收 2 个(email, nickname) |
|
||||
| CONSISTENCY-25 | 登录方式 | 前端只支持 username,后端支持 account/email/phone |
|
||||
| CONSISTENCY-26 | CSRF Token | 响应未包装,`result.code` 为 undefined |
|
||||
| CONSISTENCY-27 | Token 重试 | 401 重试所有方法(含 POST/PUT/DELETE),可能导致重复操作 |
|
||||
| CONSISTENCY-28 | OAuth 授权 | 后端返回格式不匹配 |
|
||||
| CONSISTENCY-29 | OAuth 交换 | 后端返回格式不匹配 |
|
||||
| CONSISTENCY-30 | 用户角色 | 后端返回空 stub |
|
||||
| CONSISTENCY-31 | 分配角色 | 后端返回 stub 但状态码 200 |
|
||||
| CONSISTENCY-32 | 统计接口 | 后端返回 stub |
|
||||
|
||||
#### 💭 轻微问题(8 个)
|
||||
|
||||
| ID | 类别 | 问题 |
|
||||
|----|------|------|
|
||||
| CONSISTENCY-33 | OAuth | 前端发送 `return_to` 参数,后端不读取 |
|
||||
| CONSISTENCY-34 | 短信验证码 | 前端期望 void,后端返回对象 |
|
||||
| CONSISTENCY-35 | 头像上传 | 前端期望对象,后端返回 stub |
|
||||
| CONSISTENCY-36 | 导出字段 | 前端发送逗号分隔字符串 |
|
||||
| CONSISTENCY-37 | 日志导出格式 | 格式参数传递方式需确认 |
|
||||
| CONSISTENCY-38 | TOTP 验证 | 前端期望 void,后端返回 `{verified: true}` |
|
||||
| CONSISTENCY-39 | 社交账号 | 前端期望数组,后端返回包装对象 |
|
||||
| CONSISTENCY-40 | 设备指纹 | 前端无持久化设备标识 |
|
||||
|
||||
### 2.3 正确对齐的 API(72 个端点)
|
||||
|
||||
✅ 所有 72 个端点的 URL 路径和 HTTP 方法都正确匹配。问题完全在于请求/响应载荷格式,不在于路由。
|
||||
|
||||
### 2.4 修复建议(按优先级)
|
||||
|
||||
#### P0:修复响应协议(阻塞所有功能)
|
||||
|
||||
**方案 A(推荐):添加 Gin 响应包装中间件**
|
||||
```go
|
||||
// 拦截所有 c.JSON() 调用,自动包装为 {code: 0, data: <original>, message: ""}
|
||||
func ResponseWrapper() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 包装成功响应
|
||||
// 错误响应包装为 {code: <http_status>, data: null, message: <error>}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**方案 B:重写前端 client.ts**
|
||||
移除 `result.code !== 0` 检查,直接返回 `response.json()`。
|
||||
|
||||
#### P1:标准化响应 Key
|
||||
|
||||
- 所有列表端点统一返回 `{items, total, page, page_size}`
|
||||
- 所有直接数组端点(权限树、角色权限)直接返回数组
|
||||
|
||||
#### P2:修复关键字段错位
|
||||
|
||||
| 端点 | 修复 |
|
||||
|------|------|
|
||||
| `POST /devices/me/logout-others` | 前端改为发送 `X-Device-ID` header |
|
||||
| `PUT /users/:id/password` | 前端改为发送 `old_password` |
|
||||
| `GET /auth/2fa/status` | 后端改为返回 `totp_enabled` |
|
||||
| `GET /auth/capabilities` | 后端重写响应字段名 |
|
||||
| `GET /auth/csrf-token` | 包装响应或前端直接读取 |
|
||||
|
||||
#### P3:标准化状态类型
|
||||
|
||||
- 所有状态端点统一接受数字值(0, 1, 2, 3)
|
||||
- 后端 switch 语句改为处理 `int` 而非 `string`
|
||||
|
||||
#### P4:修复分页
|
||||
|
||||
- `GET /users`: 接受 `page/page_size` 参数,内部转换为 `offset/limit`
|
||||
- 所有分页端点统一返回 `page` 和 `page_size`
|
||||
|
||||
---
|
||||
|
||||
## 三、架构性能执行审查
|
||||
|
||||
### 3.1 性能问题分类
|
||||
|
||||
#### 🔴 严重问题(7 个)
|
||||
|
||||
| ID | 类别 | 文件 | 问题 | 影响 |
|
||||
|----|------|------|------|------|
|
||||
| PERF-01 | 数据库 | `middleware/auth.go:131-197` | 认证中间件 N+1 查询:每个请求 7-8 次 DB 查询 | 1000 并发用户 = 7000-8000 DB 查询/秒 |
|
||||
| PERF-02 | 数据库 | `middleware/auth.go:210-221` | isUserActive 每次请求都执行 SELECT * | 缓存命中也无法避免 |
|
||||
| PERF-03 | 数据库 | `login_log.go:118-139` | 导出/无分页查询加载全表到内存 | 百万级日志表 OOM |
|
||||
| PERF-14 | 并发 | `auth.go:482-487` | 无界 goroutine + context.Background() | DB 降级时 goroutine 泄漏 → 连接池耗尽 |
|
||||
| PERF-28 | 架构 | `V1__init.sql` | SQLite 作为生产数据库 | 写入串行化,吞吐量上限 50-100 writes/sec |
|
||||
| PERF-29 | 架构 | `middleware/auth.go:38-47` | L1 缓存每进程独立,无法水平扩展 | 多实例部署权限变更 30 分钟传播延迟 |
|
||||
| C03 | 前端 | `client.ts:210-221` | Token 刷新重试非幂等请求 | 可能导致重复创建用户等操作 |
|
||||
|
||||
#### 🟡 重要问题(17 个)
|
||||
|
||||
| ID | 类别 | 问题 |
|
||||
|----|------|------|
|
||||
| PERF-04 | 数据库 | List() 总是 COUNT + SELECT(2 次查询),即使只需要 count |
|
||||
| PERF-05 | 数据库 | Dashboard stats 8+ 次顺序查询 |
|
||||
| PERF-06 | 数据库 | GetAncestorIDs 顺序单行查询(最多 5 层) |
|
||||
| PERF-07 | 数据库 | BatchSet 事务内 N 次顺序查询 |
|
||||
| PERF-08 | 数据库 | LIKE '%keyword%' 4 列无全文索引 |
|
||||
| PERF-09 | 数据库 | GetActiveDevices/GetTrustedDevices 无分页限制 |
|
||||
| PERF-11 | 内存 | L1Cache updateAccessOrder 使用 O(n) 切片操作 |
|
||||
| PERF-12 | 内存 | BatchDelete 未预分配切片容量 |
|
||||
| PERF-15 | 并发 | L1Cache Get 使用写锁(Lock)而非读锁(RLock) |
|
||||
| PERF-17 | HTTP | 无响应压缩中间件 |
|
||||
| PERF-18 | HTTP | 大多数路由无请求体大小限制 |
|
||||
| PERF-19 | HTTP | 操作日志中间件为每个写请求分配 4KB 缓冲 |
|
||||
| PERF-21 | Bundle | 无代码分割配置(antd + react 打包在一起) |
|
||||
| PERF-22 | Runtime | ProfileSecurityPage 946 行 mega-component |
|
||||
| PERF-23 | Runtime | WebhooksPage 客户端过滤 + 分页 |
|
||||
| PERF-26 | Network | ProfileSecurityPage 挂载时 6 个并行 API 调用,无请求去重 |
|
||||
| PERF-30 | 架构 | 无会话管理扩展性(多实例无法强制登出) |
|
||||
|
||||
#### 💭 轻微问题(8 个)
|
||||
|
||||
| ID | 类别 | 问题 |
|
||||
|----|------|------|
|
||||
| PERF-10 | 数据库 | UpdateLastLogin 使用 map[string]interface{} |
|
||||
| PERF-13 | 内存 | generateUniqueUsername 最多 1001 次顺序 DB 查询 |
|
||||
| PERF-16 | 并发 | 祖先 ID 收集未并行化 |
|
||||
| PERF-20 | HTTP | 全局 30s 超时对所有请求统一应用 |
|
||||
| PERF-24 | Runtime | UsersPage columns 未 useMemo |
|
||||
| PERF-25 | Runtime | PermissionsPage buildTreeData 每次渲染递归 |
|
||||
| PERF-27 | Network | 401 重试未检查 body 是否可流式传输 |
|
||||
| PERF-31 | 架构 | Webhook 事件通过无重试 goroutine 发布 |
|
||||
|
||||
### 3.2 前 5 大性能瓶颈
|
||||
|
||||
| 排名 | 问题 | 影响 |
|
||||
|------|------|------|
|
||||
| 1 | **SQLite 作为生产数据库** | 写入串行化,登录风暴时级联超时 |
|
||||
| 2 | **认证中间件 N+1 查询** | 每个请求 7-8 次 DB 查询,冷启动时查询风暴 |
|
||||
| 3 | **无界导出查询** | 导出端点加载全表到内存,百万级数据 OOM |
|
||||
| 4 | **Dashboard stats 顺序查询** | 8 次顺序查询,冷加载 200-500ms |
|
||||
| 5 | **泄漏的无界 goroutine** | DB 降级时 goroutine 堆积 → 连接池耗尽 → 全面宕机 |
|
||||
|
||||
### 3.3 架构扩展性评估
|
||||
|
||||
| 用户规模 | 状态 | 说明 |
|
||||
|----------|------|------|
|
||||
| 100 用户 | ✅ 就绪 | SQLite 可处理轻量并发 |
|
||||
| 1,000 用户 | ⚠️ 有风险 | 登录突发(>50/sec)会导致 SQLite 写入争用 |
|
||||
| 10,000 用户 | ❌ 不可用 | SQLite 写入串行化成为硬瓶颈,认证中间件查询量不可持续 |
|
||||
|
||||
**10,000 用户前必须完成的变更**:
|
||||
1. 迁移到 PostgreSQL
|
||||
2. 合并认证中间件查询为 1-2 次缓存查找
|
||||
3. 添加 Redis 作为共享缓存层
|
||||
4. 流式导出替代内存加载
|
||||
5. 添加自动化日志清理 cron
|
||||
|
||||
---
|
||||
|
||||
## 四、综合建议
|
||||
|
||||
### P0:立即修复(阻塞生产部署)
|
||||
|
||||
1. **修复响应格式协议不匹配**(CONSISTENCY-01)
|
||||
- 添加 Gin 响应包装中间件
|
||||
- 或重写前端 client.ts 接受裸响应
|
||||
|
||||
2. **修复关键字段错位**(CONSISTENCY-12, 13, 14, 15)
|
||||
- 设备下线:body → header
|
||||
- 修改密码:current_password → old_password
|
||||
- TOTP 状态:enabled → totp_enabled
|
||||
- Capabilities:重写后端响应字段
|
||||
|
||||
3. **修复认证中间件 N+1 查询**(PERF-01, 02)
|
||||
- 合并为单次 JOIN 查询
|
||||
- 将 user.Status 纳入缓存条目
|
||||
|
||||
4. **修复导出无界查询**(PERF-03)
|
||||
- 添加 LIMIT(如 100K 上限)
|
||||
- 或实现游标分页流式导出
|
||||
|
||||
### P1:当前迭代解决
|
||||
|
||||
5. **标准化响应 Key**(CONSISTENCY-02 到 11)
|
||||
- 所有列表端点统一 `{items, total, page, page_size}`
|
||||
|
||||
6. **标准化状态类型**(CONSISTENCY-19 到 22)
|
||||
- 后端改为接受数字值
|
||||
|
||||
7. **修复分页参数**(CONSISTENCY-23)
|
||||
- 后端接受 `page/page_size`,内部转换
|
||||
|
||||
8. **修复 Dashboard stats 查询**(PERF-05)
|
||||
- 合并为单次 GROUP BY 查询
|
||||
|
||||
9. **修复 L1Cache 并发**(PERF-15)
|
||||
- Get 使用 RLock
|
||||
|
||||
10. **修复 goroutine 泄漏**(PERF-14)
|
||||
- 添加 context.WithTimeout
|
||||
|
||||
### P2:下一轮优化
|
||||
|
||||
11. **迁移到 PostgreSQL**(PERF-28)
|
||||
12. **添加 Redis 共享缓存**(PERF-29, 30)
|
||||
13. **前端代码分割**(PERF-21)
|
||||
14. **ProfileSecurityPage 拆分**(PERF-22)
|
||||
15. **WebhooksPage 服务端过滤**(PERF-23)
|
||||
16. **添加响应压缩**(PERF-17)
|
||||
17. **实现 Stub 端点**(CONSISTENCY-30, 31, 32)
|
||||
|
||||
---
|
||||
|
||||
## 五、审查方法说明
|
||||
|
||||
本次审查采用多智能体并行模式:
|
||||
- **一致性审查智能体**: 交叉比对每个前端服务调用与后端 handler,检查 URL、方法、请求体、响应格式、错误处理、数据模型
|
||||
- **性能审查智能体**: 审查数据库查询、内存使用、并发模式、HTTP 配置、前端 bundle、运行时渲染、网络请求、架构扩展性
|
||||
|
||||
审查覆盖:
|
||||
- 前端: 13 个服务文件 + HTTP 客户端 + 类型定义
|
||||
- 后端: 所有 handler + repository + service + middleware + cache + 配置
|
||||
- 架构: 数据库选择、缓存策略、水平扩展能力
|
||||
Reference in New Issue
Block a user