13 KiB
13 KiB
全面代码审查报告
总体评价
评分:7.5 / 10
项目整体代码质量良好,架构清晰,模块职责分明。后端 Rust 代码规范,通过了 cargo clippy 零警告检查;前端 TypeScript 代码通过 tsc --noEmit 零错误,vite build 构建成功。RBAC 权限模型完整,TCP 协议处理健壮。主要不足集中在安全细节、性能优化和部分功能未完成方面。
统计
- 后端文件数:29(Rust)
- 前端文件数:35(TypeScript/TSX)
- 后端代码行数:5,162
- 前端代码行数:5,282
- 总代码行数:10,444
- 问题总数:19(严重 5 / 警告 8 / 建议 6)
静态检查结果
| 检查项 | 结果 |
|---|---|
cargo check |
通过 |
cargo clippy |
通过(零警告) |
tsc --noEmit |
通过(零错误) |
vite build |
通过(有 chunk 大小警告) |
严重问题(必须修复)
问题1:设备指令下发接口缺少权限校验
- 位置:
software/server/src/tcp/commands.rs:36-61 - 描述:
send_command端点(POST /api/devices/:dev_id/command)虽然经过认证中间件,但未调用check_permission进行 RBAC 权限校验。任何已登录用户均可向设备下发任意指令(包括开门、供电等危险操作)。 - 风险:未授权用户可操控设备,造成安全隐患。
- 建议:在
send_command函数开头添加权限校验,根据act字段判断所需权限码(如device:operate、charge:open_door` 等)。
问题2:组织树接口缺少权限校验和数据隔离
- 位置:
software/server/src/routes/cabinet_tree.rs:14-92 - 描述:
organization_tree端点未提取CurrentUser,无权限校验,也无组织级数据隔离。企业管理员可通过此接口看到所有组织的数据。 - 风险:数据泄露,违反多租户隔离原则。
- 建议:添加
CurrentUser提取器,校验device:view权限,并根据role_level和organization_id过滤返回数据。
问题3:默认密码 "123456" 硬编码
- 位置:
software/server/src/routes/users.rs:302、software/server/src/routes/users.rs:437 - 描述:创建用户和重置密码时,默认密码硬编码为
"123456"。此密码过于简单,且散落在代码中。 - 风险:安全风险,弱密码可能被暴力破解。
- 建议:将默认密码抽离为配置常量,并强制用户首次登录时修改密码。至少应使用随机生成的初始密码。
问题4:auth_str 安全码明文打印到日志
- 位置:
software/server/src/tcp/handler.rs:61 - 描述:
handle_auth_str函数将生成的安全码以明文写入日志:tracing::info!("[auth_str] dev_id={} auth_str={}", dev_id, auth_str)。 - 风险:安全码泄露,攻击者可通过日志获取签名密钥。
- 建议:移除日志中的
auth_str值,仅记录dev_id,或使用脱敏处理(如仅打印前2位)。
问题5:前端刷新后用户信息丢失
- 位置:
software/web/src/stores/auth.ts:71-76 - 描述:
restore函数仅从 localStorage 恢复 token,但未调用/api/auth/me获取用户信息和权限码。刷新页面后,虽然 token 存在,但user为 null,导致前端权限判断(hasPermission)始终返回 false,所有权限按钮消失。 - 风险:用户体验严重受损,刷新后所有权限控制按钮消失。
- 建议:在
restore中检测到 token 后,异步调用/api/auth/me恢复完整用户信息。
警告(建议修复)
警告1:前端打包体积过大
- 位置:
software/web/构建配置 - 描述:vite build 产物 JS 文件 1,314 KB(gzip 后 374 KB),超过 500 KB 警告阈值。未做代码分割。
- 建议:使用
React.lazy()+ 动态import()对路由级组件进行代码分割,尤其是 H5 端和后台管理端应分离打包。
警告2:柜子详情接口存在 N+1 查询
- 位置:
software/server/src/routes/cabinets.rs:284-308 - 描述:
get_cabinet_detail先查询仓控板列表,然后对每个仓控板单独查询仓体。若柜子有 N 块仓控板,则产生 N+1 次数据库查询。 - 建议:使用一条 SQL 通过 JOIN 查询所有仓控板和仓体,或在应用层批量查询。
警告3:角色列表接口存在 N+1 查询
- 位置:
software/server/src/routes/roles.rs:42-69 - 描述:
list_roles对每个角色单独查询权限码,产生 N+1 次查询。 - 建议:使用一条 SQL 通过 JOIN 查询所有角色及其权限码。
警告4:多处使用 as unknown as 类型断言
- 位置:
software/web/src/pages/devices/index.tsx:81,103、OrganizationTree.tsx:169,171 - 描述:前端代码中多处使用
as unknown as进行类型强转,绕过了 TypeScript 类型检查。 - 建议:修正 API 响应类型定义,使其与实际返回数据结构一致,消除不必要的类型断言。
警告5:下载文件端点未实现
- 位置:
software/server/src/routes/downloads.rs:162 - 描述:
get_download返回download_url: "/api/downloads/{id}/file",但此路由未在routes/mod.rs中注册,实际下载功能不可用。 - 建议:实现文件下载端点,使用
axum::response::File或tower-http的ServeDir提供文件服务。
警告6:org_condition 辅助函数未被充分使用
- 位置:
software/server/src/middleware/auth.rs:255-270 - 描述:
org_condition函数已定义但仅在charge_records.rs和device_logs.rs中使用。cabinet_tree.rs、energy_stats.rs等模块自行实现了类似的组织过滤逻辑,代码重复。 - 建议:统一使用
org_condition和org_condition_for_logs进行组织数据隔离,减少重复代码。
警告7:H5 用户端 API 端点后端未实现
- 位置:
software/web/src/h5/api.ts - 描述:H5 API 调用了
/h5/auth/login、/h5/dashboard、/h5/projects等端点,但后端路由中未注册这些路径。H5 用户端目前无法正常工作。 - 建议:明确 H5 后端 API 的开发计划,或在 H5 代码中标注为 WIP(Work In Progress)。
警告8:Dashboard 页面为占位符
- 位置:
software/web/src/pages/Dashboard.tsx - 描述:后台管理首页仅显示欢迎文字,无任何数据展示。能耗管理页面已有总览数据,Dashboard 应复用或引用。
- 建议:实现 Dashboard 数据展示(如今日充电次数、在线设备数、告警数等),可复用
energy-stats/summary接口。
建议(可优化)
建议1:LIKE 查询中 % 通配符未转义
- 位置:
software/server/src/routes/users.rs:111 - 描述:
let like_pattern = format!("%{}%", keyword)未对关键字中的%和_进行转义,用户输入这些字符时可能产生非预期的模糊匹配。 - 建议:对 keyword 中的
%和_进行转义后再拼接 LIKE 模式。
建议2:连接池最大连接数可配置化
- 位置:
software/server/src/db/mod.rs:11 - 描述:MySQL 连接池
max_connections(20)硬编码。 - 建议:通过环境变量
DB_MAX_CONNECTIONS配置,便于不同环境调整。
建议3:充电曲线使用静态模拟数据
- 位置:
software/web/src/h5/pages/compartment-detail.tsx:174 - 描述:通道详情页的充电曲线使用硬编码数据
[30, 45, 55, ...]展示,非真实数据。 - 建议:标注为 TODO 或待后端提供充电曲线 API 后替换,当前可接受。
建议4:log_operation 函数可抽取为公共模块
- 位置:
software/server/src/routes/users.rs:63-85 - 描述:操作日志记录函数
log_operation定义在users.rs中,但其他模块(如roles.rs、cabinets.rs)也需要记录操作日志。 - 建议:将
log_operation抽取到公共模块(如middleware/auth.rs或新建utils/log.rs),供所有路由模块复用。
建议5:前端 eslint-disable 注释
- 位置:
software/web/src/h5/pages/devices.tsx:62、device-detail.tsx:37、compartment-detail.tsx:43 - 描述:H5 页面中有多处
eslint-disable-next-line react-hooks/exhaustive-deps,跳过了 Hook 依赖检查。 - 建议:补充正确的依赖项,或使用
useCallback包裹函数以明确依赖关系。
建议6:数据库迁移缺少索引定义
- 位置:
software/server/src/db/migrate.rs - 描述:建表语句中未创建索引(除
energy_stats的联合唯一键外)。charge_records、device_logs、operation_logs等高频查询表缺少对cabinet_id、created_at等常用过滤字段的索引。 - 建议:在迁移脚本中添加索引,如:
charge_records:cabinet_id,start_timedevice_logs:cabinet_id,created_atoperation_logs:user_id,created_atcabinets:project_id
审查清单完成情况
1. 编译与类型检查
cargo check零报错零警告cargo clippy零报错零警告tsc --noEmit零报错零警告vite build成功(有 chunk 大小警告)
2. 代码规范
- 单函数基本 <=80 行(少数函数略超,如
list_users约 160 行,可拆分) - 命名语义化,无无意义缩写
- 完整注释(模块级文档注释 + 函数文档注释)
- 常量抽离(如
COST_PER_KWH、SIGN_START、TIMESTAMP_TOLERANCE_SECS) - 无废弃 API 使用
3. 错误处理
- 所有外部 IO/网络请求有异常捕获
- 无裸
panic!(expect仅用于启动阶段的致命错误,如数据库连接失败) - 分支逻辑基本全覆盖
- 错误信息有意义(使用中文描述,含上下文)
4. Rust 专项
- 内存安全,使用 sqlx 连接池无冗余拷贝
- 无
unsafe块 - 所有权管理合理(
ConnectionPool使用Arc<RwLock<>>共享) - 异步代码无阻塞操作
5. React 专项
- 函数式组件 + Hooks,无 Class 组件
- 状态管理使用 Zustand,分层清晰
- useEffect 有清理函数(如 DownloadCenter 的 setInterval)
- 少量
as unknown as类型断言(见警告4)
6. 安全
- SQL 注入防护(全部使用
?参数化查询) - 密码哈希使用 argon2
- JWT 密钥有环境变量覆盖机制 + 警告
- 输入参数校验(手机号 11 位、IMEI 15 位等)
- 权限校验未覆盖所有 API 接口(见严重问题 1、2)
- 数据隔离部分缺失(见严重问题 2)
- 敏感参数脱敏不足(见严重问题 4)
7. 业务逻辑
- TCP 协议解析正确(签名验证、LF 粘包处理、超时清理)
- 权限模型正确(总管理员/企业管理员/普通用户三级)
- 异步导出流程完整(任务创建 -> 后台处理 -> 下载中心)
- 前端权限组件正确隐藏/禁用按钮
8. 架构
- 接口层、业务逻辑层、数据模型层分离
- 无循环依赖
- 模块职责清晰
- 路由注册完整
9. 性能
- 数据库查询缺少索引(见建议 6)
- 存在 N+1 查询(见警告 2、3)
- 前端列表有分页
- 大数据量导出异步处理
10. 可维护性
- 文件长度合理(最长 467 行 energy/index.tsx)
- 组件拆分合理
- 代码重复度低(组织过滤逻辑有重复,见警告 6)
- 配置外部化(环境变量 + dotenvy)
优点
- 架构清晰:后端按功能域拆分模块(auth、organizations、cabinets、users 等),每个文件职责单一,不超过 500 行。
- 安全性基础扎实:密码使用 argon2 哈希、JWT 有过期时间、SQL 全部参数化、TCP 签名验证含时间窗口校验。
- RBAC 权限模型完整:权限码精确到按钮级别,前端
Permission组件支持 hidden/disabled 两种模式,总管理员自动拥有全部权限。 - TCP 协议处理健壮:使用
LinesCodec处理粘包、mpsc通道分离读写、心跳超时自动清理、连接池Arc<RwLock>支持并发。 - 异步导出设计合理:download_tasks 表管理任务状态、tokio::spawn 后台生成 Excel、前端轮询刷新、过期文件清理。
- 前端工程化规范:Zustand 状态管理简洁、API 层统一封装、路由守卫完善、H5 端与后台管理端独立认证。
- 代码注释充分:每个模块有模块级文档注释,关键函数有入参/返回值说明,复杂逻辑有行内注释。
- 数据库迁移自动化:启动时自动建表 + 初始化权限码和角色,部署友好。
总结
项目整体质量良好,代码规范、架构清晰、安全基础扎实。优先修复建议:
- P0(立即修复):设备指令下发接口添加权限校验(严重问题 1)、组织树接口添加权限校验和数据隔离(严重问题 2)。
- P1(尽快修复):前端 restore 后加载用户信息(严重问题 5)、auth_str 日志脱敏(严重问题 4)、默认密码安全化(严重问题 3)。
- P2(迭代优化):N+1 查询优化、数据库索引添加、前端代码分割、下载文件端点实现、Dashboard 数据填充。
- P3(后续完善):H5 后端 API 开发、操作日志函数抽取公共模块、LIKE 通配符转义。