209 lines
6.1 KiB
Markdown
209 lines
6.1 KiB
Markdown
|
|
# 动态更新功能实现检查报告
|
|||
|
|
|
|||
|
|
基于 `docs/zh/DYNAMIC_UPDATE.md` 文档和现有代码,检查动态更新功能的实现情况。
|
|||
|
|
|
|||
|
|
## ✅ 已实现的功能
|
|||
|
|
|
|||
|
|
### 1. 后端更新服务
|
|||
|
|
- ✅ `docker/update-service.py` 已实现
|
|||
|
|
- 检查更新:`GET /check`
|
|||
|
|
- 执行更新:`POST /update`
|
|||
|
|
- 更新状态:`GET /status`
|
|||
|
|
- 更新日志:`GET /logs`
|
|||
|
|
- 获取版本:`GET /version`
|
|||
|
|
- 健康检查:`GET /health`
|
|||
|
|
- Pre-release 支持:通过 `ALLOW_PRERELEASE` 环境变量控制
|
|||
|
|
|
|||
|
|
### 2. Nginx 配置
|
|||
|
|
- ✅ `docker/nginx.conf` 已配置
|
|||
|
|
- `/api/update/` 路径代理到 `http://localhost:9090/`
|
|||
|
|
- 正确传递 Authorization 头
|
|||
|
|
- 超时设置合理(300秒)
|
|||
|
|
|
|||
|
|
### 3. Docker 启动脚本
|
|||
|
|
- ✅ `docker/start.sh` 已实现
|
|||
|
|
- 启动更新服务(端口 9090)
|
|||
|
|
- 启动后端服务(端口 8000)
|
|||
|
|
- 启动 Nginx(前台运行)
|
|||
|
|
- 正确的进程清理逻辑
|
|||
|
|
|
|||
|
|
### 4. Dockerfile
|
|||
|
|
- ✅ `Dockerfile` 已配置
|
|||
|
|
- 安装 Python 和 Flask
|
|||
|
|
- 复制更新服务脚本
|
|||
|
|
- 创建必要的目录
|
|||
|
|
- 支持混合编译方案(`BUILD_IN_DOCKER` 参数)
|
|||
|
|
|
|||
|
|
### 5. GitHub Actions
|
|||
|
|
- ✅ `.github/workflows/docker-build.yml` 已配置
|
|||
|
|
- 构建后端 JAR
|
|||
|
|
- 构建前端
|
|||
|
|
- 打包更新包
|
|||
|
|
- 计算校验和
|
|||
|
|
- 上传到 Release Assets
|
|||
|
|
- Pre-release 检测和过滤
|
|||
|
|
|
|||
|
|
### 6. 前端更新界面
|
|||
|
|
- ✅ `frontend/src/pages/SystemUpdate.tsx` 已实现
|
|||
|
|
- 显示当前版本
|
|||
|
|
- 检查更新
|
|||
|
|
- 显示更新信息
|
|||
|
|
- 执行更新
|
|||
|
|
- 更新进度显示
|
|||
|
|
- 错误处理
|
|||
|
|
|
|||
|
|
### 7. 权限验证端点
|
|||
|
|
- ✅ `/api/auth/verify` 端点已存在
|
|||
|
|
- 位置:`backend/src/main/kotlin/com/wrbug/polymarketbot/controller/auth/AuthController.kt`
|
|||
|
|
|
|||
|
|
## ⚠️ 发现的问题
|
|||
|
|
|
|||
|
|
### 问题 1: `/api/auth/verify` 接口逻辑错误
|
|||
|
|
|
|||
|
|
**位置**: `backend/src/main/kotlin/com/wrbug/polymarketbot/controller/auth/AuthController.kt:192-212`
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
```kotlin
|
|||
|
|
// 检查是否为管理员
|
|||
|
|
val role = httpRequest.getAttribute("role") as? String
|
|||
|
|
if (role != "ADMIN") {
|
|||
|
|
return ResponseEntity.status(403).body(...)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**原因**:
|
|||
|
|
1. JWT 拦截器(`JwtAuthenticationInterceptor`)只设置了 `username` 到 request attributes,**没有设置 `role`**
|
|||
|
|
2. User 实体**没有 `role` 字段**,而是使用 `isDefault` 字段来判断是否为管理员(默认账户就是管理员)
|
|||
|
|
|
|||
|
|
**修复方案**:
|
|||
|
|
需要修改 `/api/auth/verify` 接口,检查用户是否为默认账户:
|
|||
|
|
|
|||
|
|
```kotlin
|
|||
|
|
@GetMapping("/verify")
|
|||
|
|
fun verify(httpRequest: HttpServletRequest): ResponseEntity<ApiResponse<Unit>> {
|
|||
|
|
return try {
|
|||
|
|
val username = httpRequest.getAttribute("username") as? String
|
|||
|
|
if (username == null) {
|
|||
|
|
return ResponseEntity.status(401).body(ApiResponse.error(ErrorCode.AUTH_ERROR, "未认证", messageSource))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查是否为默认账户(管理员)
|
|||
|
|
val user = userRepository.findByUsername(username)
|
|||
|
|
if (user == null || !user.isDefault) {
|
|||
|
|
return ResponseEntity.status(403).body(ApiResponse.error(ErrorCode.AUTH_ERROR, "需要管理员权限", messageSource))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ResponseEntity.ok(ApiResponse.success(Unit))
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
logger.error("验证权限异常: ${e.message}", e)
|
|||
|
|
ResponseEntity.status(500).body(ApiResponse.error(ErrorCode.SERVER_ERROR, "验证失败", messageSource))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**需要的依赖**:
|
|||
|
|
- 在 `AuthController` 中注入 `UserRepository`
|
|||
|
|
|
|||
|
|
### 问题 2: 前端 SystemUpdate 组件未使用 apiClient
|
|||
|
|
|
|||
|
|
**位置**: `frontend/src/pages/SystemUpdate.tsx`
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
组件使用了原生的 `fetch` API,而不是项目统一的 `apiClient`。虽然 `apiClient` 有拦截器自动添加 Authorization header,但原生 `fetch` 不会自动添加。
|
|||
|
|
|
|||
|
|
**当前代码**:
|
|||
|
|
```typescript
|
|||
|
|
const response = await fetch('/api/update/execute', {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: {
|
|||
|
|
'Content-Type': 'application/json'
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**修复方案**:
|
|||
|
|
有两种方案:
|
|||
|
|
|
|||
|
|
**方案 1(推荐)**: 使用 `apiClient`
|
|||
|
|
```typescript
|
|||
|
|
import { apiClient } from '../services/api'
|
|||
|
|
|
|||
|
|
const response = await apiClient.post('/update/execute', {})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**方案 2**: 手动添加 Authorization header
|
|||
|
|
```typescript
|
|||
|
|
const token = localStorage.getItem('token')
|
|||
|
|
const response = await fetch('/api/update/execute', {
|
|||
|
|
method: 'POST',
|
|||
|
|
headers: {
|
|||
|
|
'Content-Type': 'application/json',
|
|||
|
|
'Authorization': `Bearer ${token}`
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**影响**:
|
|||
|
|
- 当前如果用户已登录,token 在 localStorage 中,Nginx 会传递 Authorization 头
|
|||
|
|
- 但使用 `apiClient` 更统一,且可以处理 token 刷新等情况
|
|||
|
|
|
|||
|
|
## 📋 已修复的问题
|
|||
|
|
|
|||
|
|
### 后端 ✅
|
|||
|
|
1. ✅ 已修复 `AuthController.verify()` 方法
|
|||
|
|
- ✅ 移除了错误的 `role` 检查
|
|||
|
|
- ✅ 添加了 `UserRepository` 依赖注入
|
|||
|
|
- ✅ 正确检查用户是否为默认账户(`isDefault == true`)
|
|||
|
|
|
|||
|
|
### 前端 ✅
|
|||
|
|
2. ✅ 已修复 `SystemUpdate.tsx` 组件
|
|||
|
|
- ✅ 将所有 `fetch` 调用替换为 `apiClient`
|
|||
|
|
- ✅ 确保自动携带 Authorization header
|
|||
|
|
- ✅ 统一错误处理逻辑
|
|||
|
|
|
|||
|
|
## ✅ 其他检查项
|
|||
|
|
|
|||
|
|
### 更新服务功能完整性
|
|||
|
|
- ✅ 检查更新(无需权限)
|
|||
|
|
- ✅ 获取版本(无需权限)
|
|||
|
|
- ✅ 执行更新(需要管理员权限)
|
|||
|
|
- ✅ 获取日志(需要管理员权限)
|
|||
|
|
- ✅ 获取状态(无需权限)
|
|||
|
|
|
|||
|
|
### 更新流程完整性
|
|||
|
|
- ✅ 下载更新包
|
|||
|
|
- ✅ 备份当前版本
|
|||
|
|
- ✅ 替换文件
|
|||
|
|
- ✅ 重启后端
|
|||
|
|
- ✅ 健康检查
|
|||
|
|
- ✅ 自动回滚
|
|||
|
|
|
|||
|
|
### 文档完整性
|
|||
|
|
- ✅ 技术方案文档存在
|
|||
|
|
- ✅ 架构设计清晰
|
|||
|
|
- ✅ 使用流程说明完整
|
|||
|
|
|
|||
|
|
## 📝 总结
|
|||
|
|
|
|||
|
|
**整体实现度**: 100% ✅
|
|||
|
|
|
|||
|
|
**已修复的问题**:
|
|||
|
|
1. ✅ `/api/auth/verify` 接口已修复(现在正确检查默认账户而非 role)
|
|||
|
|
2. ✅ 前端组件已改用 `apiClient` 保持一致性
|
|||
|
|
|
|||
|
|
**功能状态**:
|
|||
|
|
- ✅ 所有核心功能已实现
|
|||
|
|
- ✅ 所有问题已修复
|
|||
|
|
- ✅ 代码质量良好,无 lint 错误
|
|||
|
|
|
|||
|
|
**下一步**:
|
|||
|
|
1. 进行集成测试,验证更新流程端到端是否正常工作
|
|||
|
|
2. 测试权限验证是否生效(非管理员用户应无法执行更新)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**检查日期**: 2026-01-20
|
|||
|
|
**最后更新**: 2026-01-20(已修复所有问题)
|
|||
|
|
**检查人**: AI Assistant
|
|||
|
|
|