charging-cabinet/tasks/review-code-quality.md

123 lines
7.3 KiB
Markdown
Raw Normal View History

# 代码审查报告
**审查日期**2026-07-01
**审查范围**`software/server/src/`Rust + Axum`software/web/src/`React + TypeScript
**审查工具**`cargo check``cargo clippy``tsc --noEmit`、人工审计
---
## 总体评价7.5 / 10
项目整体架构清晰分层合理错误处理较为完善。Rust 端无裸 `panic!` / `.unwrap()`,前端无 `as any`。主要问题集中在:**SQL 注入风险**、**数据隔离缺失**、**权限校验不完整**、**部分文件过长**。
---
## 严重问题(🔴 必须修复)
### 问题 1操作日志查询存在 SQL 注入风险
- **位置**`src/routes/operation_logs.rs:49-63`
- **描述**`action``start_time``end_time` 参数通过 `format!` 直接拼接到 SQL WHERE 子句中,虽然做了 `'` 替换,但仍可被绕过(如 `1; DROP TABLE users--`)。
- **风险**:攻击者可注入任意 SQL 语句,导致数据泄露或破坏。
- **建议**:改用 `sqlx::query_as` 的参数化绑定,或将条件构建逻辑统一为 `build_where_clause` 模式(如 `charge_records.rs` 已实现的那样)。
### 问题 2充电记录 LIMIT/OFFSET 通过 format! 拼接
- **位置**`src/routes/charge_records.rs:130`
- **描述**`LIMIT {} OFFSET {}` 直接使用 `format!` 拼接 `i64` 参数。虽然参数类型是 `i64`,但若未来参数类型变更或被误传字符串,将产生注入。
- **风险**:中等(当前类型安全,但模式脆弱)。
- **建议**:将 `limit` / `offset` 也通过 `.bind()` 传入。
### 问题 3无组织/项目级数据隔离
- **位置**`src/routes/organizations.rs` 全部路由、`src/routes/charge_records.rs``src/routes/device_logs.rs``src/routes/energy_stats.rs`
- **描述**:所有查询均无 `WHERE organization_id = ?``WHERE project_id = ?` 过滤。企业管理员可以查看所有组织的数据,而非仅其管辖范围。
- **风险**:高。多租户场景下,企业 A 的管理员可以看到企业 B 的所有设备和数据。
- **建议**:在 `CurrentUser` 中携带 `organization_id`,在所有查询中自动附加 `WHERE organization_id = ?` 过滤。
### 问题 4部分路由缺少权限校验
- **位置**`src/routes/charge_records.rs:158``src/routes/device_logs.rs:62``src/routes/energy_stats.rs:81-283``src/routes/downloads.rs:87``src/routes/organizations.rs:144-551`
- **描述**:这些路由处理器未调用 `auth::check_permission()`,仅依赖 JWT 认证中间件。任何登录用户均可访问充电记录、设备日志、能耗统计、下载中心等敏感数据。
- **风险**:中。越权访问非管理类功能。
- **建议**:为每个路由添加对应的 `check_permission` 调用,如 `user:view``energy:view` 等。
### 问题 5密码明文存储
- **位置**`src/routes/auth.rs:51`
- **描述**`stored_password != input.password` 直接比较明文。代码注释也明确写道"后续应改为 bcrypt/argon2 哈希"。
- **风险**:高。数据库泄露即所有用户密码暴露。
- **建议**:集成 `argon2``bcrypt` crate在登录时 `argon2::verify`,在创建/重置时 `argon2::hash`
---
## 警告(🟡 建议修复)
### 警告 1organizations.rs 文件过长693 行)
- **位置**`src/routes/organizations.rs`
- **描述**:单个文件 693 行,包含组织/项目/柜子 CRUD + 树状结构 + 柜子详情,职责过多。
- **建议**:拆分为 `organizations.rs``projects.rs``cabinets.rs` 三个文件。
### 警告 2users.rs 文件过长495 行)
- **位置**`src/routes/users.rs`
- **描述**:包含用户 CRUD、密码重置、状态管理、操作日志记录超过 80 行/函数约束(部分辅助函数虽短,但整体文件过大)。
- **建议**:将 `log_operation` 辅助函数提取到独立模块。
### 警告 3JWT 默认密钥在生产环境可能泄露
- **位置**`src/middleware/auth.rs:28`
- **描述**`JWT_SECRET_DEFAULT = "pms-dev-secret-change-me-in-production"` 如果环境变量未设置,将使用此默认值。
- **建议**:启动时若检测到默认密钥,打印 WARN 日志;或在 `config.rs` 中将 JWT_SECRET 设为必填。
### 警告 4energy_stats 导出 LIMIT/OFFSET 同样存在 format! 拼接
- **位置**`src/routes/energy_stats.rs:341`
- **描述**:与 charge_records.rs 相同的问题LIMIT/OFFSET 通过 `format!` 拼接。
- **建议**:统一使用参数化绑定。
### 警告 5devices/index.tsx 文件过长631 行)
- **位置**`src/pages/devices/index.tsx`
- **描述**:单个 TSX 文件 631 行包含组织树、柜子列表、CRUD 弹窗、右键菜单、批量添加等全部逻辑。
- **建议**:提取 `OrganizationalTree.tsx``CabinetGrid.tsx``AddCabinetModal.tsx` 为独立组件。
### 警告 6Pre-existing 构建错误IconFolderOpen
- **位置**`src/pages/devices/index.tsx:33`
- **描述**`IconFolderOpen``@arco-design/web-react/icon` 导入,但该版本未导出此图标。导致 `vite build` 失败。
- **风险**:前端无法构建生产包。
- **建议**:替换为 `IconFolder` 或其他可用图标。
### 警告 7clippy 警告 15 条
- **位置**:多处
- **描述**:主要包括 `collapsible_if`(可折叠嵌套 if`type_complexity`(复杂类型未抽取 type alias`manual_unwrap_or_default``obfuscated_if_else` 等。
- **建议**:运行 `cargo clippy --fix` 自动修复大部分问题。
### 警告 8前端 H5 页面中充电曲线为静态 Mock 数据
- **位置**`src/h5/pages/compartment-detail.tsx:156`
- **描述**:充电曲线使用硬编码的模拟数据 `[30, 45, 55, ...]`,后端未提供实时充电曲线数据。
- **建议**:待后端提供数据后替换为真实折线图。
---
## 优点
1. **Rust 错误处理规范**:无裸 `panic!` / `.unwrap()`,使用 `Result``?` 运算符,业务逻辑层错误处理完善。
2. **统一错误类型**`AppError` enum 覆盖所有错误场景,`IntoResponse` 实现统一返回格式。
3. **TCP 协议处理健壮**签名验证SHA256 + 时间窗、粘包处理LF 分隔)、连接超时清理。
4. **RBAC 权限模型**JWT + 权限码 + 角色等级(总管理员自动拥有全部权限),设计合理。
5. **前端类型安全**:无 `as any`,完整的 TypeScript 接口定义。
6. **H5 用户端实现简洁**Tailwind CSS 自定义组件,零新增依赖,扫码入口自动路由。
7. **异步导出流程完整**:任务创建 → 后台 tokio::spawn 生成 Excel → 状态更新 → 下载。
---
## 总结
| 维度 | 评分 | 说明 |
|------|------|------|
| 编译/类型检查 | 9/10 | Rust clippy 15 条警告,前端 tsc 零错误IconFolderOpen 预存问题) |
| 代码规范 | 7/10 | 部分文件过长,单函数基本在 80 行以内 |
| 错误处理 | 8/10 | Rust 端优秀,前端 try/catch 覆盖全面 |
| 安全性 | 5/10 | SQL 注入风险、明文密码、数据隔离缺失 |
| 架构设计 | 8/10 | 分层清晰路由模块化TCP 协议处理得当 |
**优先级排序**
1. 🔴 修复 SQL 注入operation_logs、energy_stats、charge_records
2. 🔴 实现密码哈希argon2/bcrypt
3. 🔴 添加组织级数据隔离
4. 🟡 补充缺失的权限校验
5. 🟡 修复 IconFolderOpen 构建错误
6. 🟡 拆分大文件organizations.rs、users.rs、devices/index.tsx