feat: 实现 AMT 设备自动添加功能(仅 Digest 认证)
- 添加 AMT Digest 认证服务 (AmtDigestService) - 添加 AMT 模拟服务用于测试 (AmtMockService) - 更新设备控制器支持 AMT 连接测试和设备信息获取 - 前端添加 AMT 自动添加方式,支持手动输入和凭证选择 - 移除 Basic 认证,仅使用 Digest 认证 - 添加 Apache HttpClient 依赖支持 Digest 认证 - 创建相关文档和测试脚本
This commit is contained in:
parent
7d3f98e4f0
commit
8b07d8f52a
0
.kiro/specs/amt-device-addition/requirements.md
Normal file
0
.kiro/specs/amt-device-addition/requirements.md
Normal file
245
AMT_DEVICE_ADD_FEATURE.md
Normal file
245
AMT_DEVICE_ADD_FEATURE.md
Normal file
@ -0,0 +1,245 @@
|
||||
# AMT 设备添加功能说明
|
||||
|
||||
## 功能概述
|
||||
|
||||
在设备管理的设备列表页面,增强了"新增设备"功能,支持通过 Intel AMT(Active Management Technology)协议自动发现和添加设备。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 1. 两种添加方式
|
||||
|
||||
#### 手动添加
|
||||
- 传统的手动输入设备信息方式
|
||||
- 需要手动填写设备名称、UUID、IP地址、MAC地址等信息
|
||||
|
||||
#### AMT 自动添加
|
||||
- 通过 AMT 协议自动发现设备
|
||||
- 只需输入 IP 地址和认证信息
|
||||
- 自动获取设备名称、MAC 地址等信息
|
||||
- 自动生成 UUID
|
||||
|
||||
### 2. 认证方式
|
||||
|
||||
#### 直接输入
|
||||
- 手动输入 AMT 用户名和密码
|
||||
- 适合临时测试或一次性添加
|
||||
|
||||
#### 使用已保存凭证
|
||||
- 从"AMT 设置"页面选择已保存的凭证
|
||||
- 支持默认凭证快速选择
|
||||
- 提高安全性和便捷性
|
||||
|
||||
### 3. 连接测试
|
||||
|
||||
- 提供"测试连接"按钮
|
||||
- 验证 AMT 连接是否可用
|
||||
- 测试成功后自动获取设备信息
|
||||
- 显示连接状态反馈
|
||||
|
||||
## 技术实现
|
||||
|
||||
### 后端实现
|
||||
|
||||
#### 1. AmtDigestService.java
|
||||
- 使用 WS-Management 协议与 AMT 设备通信
|
||||
- 支持 Digest 认证(HTTP Digest Auth)
|
||||
- 实现设备信息获取和连接测试
|
||||
|
||||
#### 2. 主要接口
|
||||
|
||||
**测试 AMT 连接**
|
||||
```
|
||||
POST /device/amt/test
|
||||
{
|
||||
"ipAddress": "192.168.1.100",
|
||||
"username": "admin",
|
||||
"password": "password"
|
||||
}
|
||||
或
|
||||
{
|
||||
"ipAddress": "192.168.1.100",
|
||||
"credentialId": 1
|
||||
}
|
||||
```
|
||||
|
||||
**获取 AMT 设备信息**
|
||||
```
|
||||
POST /device/amt/getInfo
|
||||
{
|
||||
"ipAddress": "192.168.1.100",
|
||||
"username": "admin",
|
||||
"password": "password"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. WS-Management 协议
|
||||
|
||||
使用标准的 SOAP over HTTP 协议:
|
||||
- 端口:HTTP 16992, HTTPS 16993
|
||||
- 认证:HTTP Digest Authentication
|
||||
- 协议:WS-Management (WSMAN)
|
||||
|
||||
### 前端实现
|
||||
|
||||
#### 1. 设备列表页面增强
|
||||
- 添加方式选择(单选按钮)
|
||||
- AMT 设备发现表单
|
||||
- 认证方式切换(开关)
|
||||
- 凭证选择下拉框
|
||||
- 测试连接按钮和状态显示
|
||||
|
||||
#### 2. 用户交互流程
|
||||
|
||||
1. 点击"新增设备"按钮
|
||||
2. 选择"AMT 自动添加"方式
|
||||
3. 输入 IP 地址
|
||||
4. 选择认证方式:
|
||||
- 手动输入:填写用户名和密码
|
||||
- 使用凭证:从下拉框选择已保存的凭证
|
||||
5. 点击"测试连接"
|
||||
6. 连接成功后,自动填充设备信息
|
||||
7. 确认并保存设备
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 前置条件
|
||||
|
||||
1. AMT 设备已启用并配置
|
||||
2. AMT 设备网络可达
|
||||
3. 已知 AMT 管理员账号密码
|
||||
4. (可选)在"AMT 设置"中预先保存凭证
|
||||
|
||||
### 操作步骤
|
||||
|
||||
1. **进入设备列表页面**
|
||||
- 导航到:设备管理 > 设备列表
|
||||
|
||||
2. **点击新增设备**
|
||||
- 点击页面右上角的"新增设备"按钮
|
||||
|
||||
3. **选择 AMT 自动添加**
|
||||
- 在弹出的对话框中选择"AMT 自动添加"单选按钮
|
||||
|
||||
4. **输入 AMT 设备信息**
|
||||
- IP 地址:输入 AMT 设备的 IP 地址
|
||||
- 认证方式:
|
||||
- 方式一:切换到"手动输入",填写用户名和密码
|
||||
- 方式二:切换到"使用已保存凭证",从下拉框选择凭证
|
||||
|
||||
5. **测试连接**
|
||||
- 点击"测试连接"按钮
|
||||
- 等待测试结果
|
||||
- 成功后会显示绿色的"连接成功"标签
|
||||
|
||||
6. **确认设备信息**
|
||||
- 系统自动填充设备名称、UUID、IP地址、MAC地址
|
||||
- 可以修改设备名称和备注
|
||||
- 选择设备状态
|
||||
|
||||
7. **保存设备**
|
||||
- 点击"确定"按钮保存设备
|
||||
|
||||
### 注意事项
|
||||
|
||||
1. **网络连接**
|
||||
- 确保服务器能够访问 AMT 设备的 16992 端口
|
||||
- 检查防火墙设置
|
||||
|
||||
2. **AMT 配置**
|
||||
- AMT 设备必须已启用并配置
|
||||
- 确认 AMT 管理员账号可用
|
||||
|
||||
3. **安全性**
|
||||
- 建议使用已保存的凭证而不是每次手动输入
|
||||
- 定期更新 AMT 密码
|
||||
|
||||
4. **错误处理**
|
||||
- 连接失败时会显示具体错误信息
|
||||
- 常见错误:
|
||||
- 网络不可达
|
||||
- 认证失败
|
||||
- AMT 未启用
|
||||
|
||||
## 文件清单
|
||||
|
||||
### 后端文件
|
||||
- `backend/src/main/java/com/soybean/admin/service/AmtDigestService.java` - AMT Digest 认证服务
|
||||
- `backend/src/main/java/com/soybean/admin/dto/AmtTestRequest.java` - 测试请求 DTO
|
||||
- `backend/src/main/java/com/soybean/admin/dto/AmtDeviceInfo.java` - 设备信息 DTO
|
||||
- `backend/src/main/java/com/soybean/admin/controller/DeviceController.java` - 设备控制器(已更新)
|
||||
|
||||
### 前端文件
|
||||
- `src/views/device/list/index.vue` - 设备列表页面(已更新)
|
||||
- `src/service/api/device.ts` - 设备 API(已更新)
|
||||
- `src/typings/api/device.d.ts` - 设备类型定义(已更新)
|
||||
|
||||
### 工具文件
|
||||
- `rebuild_and_test_amt.bat` - 重新编译和测试脚本
|
||||
- `AMT_DEVICE_ADD_FEATURE.md` - 本说明文档
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **单元测试**
|
||||
- 测试 AMT 连接功能
|
||||
- 测试设备信息获取
|
||||
- 测试凭证集成
|
||||
|
||||
2. **集成测试**
|
||||
- 使用真实 AMT 设备测试
|
||||
- 测试不同的认证方式
|
||||
- 测试错误处理
|
||||
|
||||
3. **用户测试**
|
||||
- 测试完整的添加流程
|
||||
- 验证用户体验
|
||||
- 收集反馈
|
||||
|
||||
## 未来改进
|
||||
|
||||
1. **批量发现**
|
||||
- 支持 IP 段扫描
|
||||
- 批量添加多个设备
|
||||
|
||||
2. **更多设备信息**
|
||||
- 获取 CPU、内存等硬件信息
|
||||
- 获取 AMT 版本信息
|
||||
- 获取设备序列号
|
||||
|
||||
3. **高级功能**
|
||||
- 支持 TLS 加密连接
|
||||
- 支持证书认证
|
||||
- 支持 Kerberos 认证
|
||||
|
||||
4. **监控集成**
|
||||
- 定期检查设备状态
|
||||
- AMT 事件日志收集
|
||||
- 设备健康度监控
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 问题:连接超时
|
||||
**原因**:网络不可达或防火墙阻止
|
||||
**解决**:
|
||||
- 检查网络连接
|
||||
- 确认防火墙规则
|
||||
- 验证 AMT 端口 16992 是否开放
|
||||
|
||||
### 问题:认证失败
|
||||
**原因**:用户名或密码错误
|
||||
**解决**:
|
||||
- 确认 AMT 管理员账号
|
||||
- 重置 AMT 密码
|
||||
- 检查凭证配置
|
||||
|
||||
### 问题:无法获取设备信息
|
||||
**原因**:AMT 未完全配置或版本不兼容
|
||||
**解决**:
|
||||
- 检查 AMT 配置状态
|
||||
- 确认 AMT 版本
|
||||
- 查看 AMT 日志
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Intel AMT SDK Documentation](https://software.intel.com/sites/manageability/)
|
||||
- [WS-Management Protocol](https://www.dmtf.org/standards/ws-man)
|
||||
- [Intel vPro Technology](https://www.intel.com/content/www/us/en/architecture-and-technology/vpro/vpro-technology-general.html)
|
||||
221
AMT_NO_LOGS_FIX.md
Normal file
221
AMT_NO_LOGS_FIX.md
Normal file
@ -0,0 +1,221 @@
|
||||
# AMT 功能无日志问题修复指南
|
||||
|
||||
## 问题描述
|
||||
|
||||
点击"测试连接"后,后端没有任何日志输出,直接显示超时错误。
|
||||
|
||||
## 可能原因
|
||||
|
||||
1. **代码未编译**:新添加的代码没有被编译
|
||||
2. **后端未重启**:修改后没有重启后端服务
|
||||
3. **请求未到达后端**:前端请求没有正确发送到后端
|
||||
4. **端口问题**:后端端口被占用或配置错误
|
||||
|
||||
## 解决步骤
|
||||
|
||||
### 步骤 1:停止当前后端服务
|
||||
|
||||
如果后端正在运行,先停止它:
|
||||
- 在运行后端的命令行窗口按 `Ctrl+C`
|
||||
- 或者关闭运行后端的窗口
|
||||
|
||||
### 步骤 2:重新编译并启动后端
|
||||
|
||||
运行以下脚本:
|
||||
|
||||
```batch
|
||||
rebuild_backend_with_logs.bat
|
||||
```
|
||||
|
||||
这个脚本会:
|
||||
1. 清理旧的编译文件
|
||||
2. 重新编译所有代码
|
||||
3. 启动后端服务并显示详细日志
|
||||
|
||||
### 步骤 3:验证后端是否正常运行
|
||||
|
||||
在新的命令行窗口运行:
|
||||
|
||||
```batch
|
||||
test_amt_api.bat
|
||||
```
|
||||
|
||||
这个脚本会测试:
|
||||
1. 后端是否运行
|
||||
2. AMT API 是否可访问
|
||||
3. 模拟模式状态
|
||||
|
||||
### 步骤 4:查看日志输出
|
||||
|
||||
启动后端后,你应该能看到类似的日志:
|
||||
|
||||
```
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [main] c.s.a.Application : Starting Application
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [main] c.s.a.Application : Started Application in x.xxx seconds
|
||||
```
|
||||
|
||||
当你点击"测试连接"时,应该看到:
|
||||
|
||||
```
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.c.DeviceController : 收到 AMT 测试连接请求,IP: 192.168.1.100, 模拟模式: false
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.c.DeviceController : 使用真实 AMT 服务测试连接
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.s.AmtService : 开始测试 AMT 连接,IP: 192.168.1.100
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.s.AmtService : 使用手动输入的凭证,用户名: admin
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.s.AmtService : 准备发送 WS-Management 请求到: 192.168.1.100
|
||||
```
|
||||
|
||||
### 步骤 5:如果仍然没有日志
|
||||
|
||||
#### 5.1 检查后端是否真的在运行
|
||||
|
||||
```batch
|
||||
netstat -ano | findstr 8080
|
||||
```
|
||||
|
||||
应该看到端口 8080 被占用。
|
||||
|
||||
#### 5.2 检查前端请求是否发送
|
||||
|
||||
打开浏览器开发者工具(F12),切换到 Network 标签,点击"测试连接",查看是否有请求发送到 `/device/amt/test`。
|
||||
|
||||
#### 5.3 检查请求 URL
|
||||
|
||||
确认前端请求的 URL 是:
|
||||
```
|
||||
POST http://localhost:8080/device/amt/test
|
||||
```
|
||||
|
||||
#### 5.4 检查 CORS 问题
|
||||
|
||||
如果看到 CORS 错误,需要在后端添加 CORS 配置。
|
||||
|
||||
### 步骤 6:使用模拟模式测试
|
||||
|
||||
如果真实 AMT 连接有问题,先用模拟模式测试功能:
|
||||
|
||||
#### 方法 1:修改代码
|
||||
|
||||
编辑 `backend/src/main/java/com/soybean/admin/controller/DeviceController.java`:
|
||||
|
||||
```java
|
||||
// 将这一行
|
||||
private boolean useMockMode = false;
|
||||
|
||||
// 改为
|
||||
private boolean useMockMode = true;
|
||||
```
|
||||
|
||||
然后重新编译并启动。
|
||||
|
||||
#### 方法 2:使用 API 切换
|
||||
|
||||
发送 POST 请求:
|
||||
|
||||
```batch
|
||||
curl -X POST http://localhost:8080/device/amt/toggleMock
|
||||
```
|
||||
|
||||
或者在浏览器中访问:
|
||||
```
|
||||
http://localhost:8080/device/amt/toggleMock
|
||||
```
|
||||
|
||||
### 步骤 7:测试模拟模式
|
||||
|
||||
启用模拟模式后:
|
||||
1. IP 地址:任意(如 192.168.1.100)
|
||||
2. 用户名:`admin`
|
||||
3. 密码:`admin`
|
||||
4. 点击"测试连接"
|
||||
|
||||
应该会成功并显示日志:
|
||||
|
||||
```
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.c.DeviceController : 收到 AMT 测试连接请求,IP: 192.168.1.100, 模拟模式: true
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.c.DeviceController : 使用模拟模式测试连接
|
||||
2024-xx-xx xx:xx:xx.xxx INFO xxxxx --- [http-nio-8080-exec-1] c.s.a.c.DeviceController : AMT 测试连接结果: true
|
||||
```
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 编译失败
|
||||
|
||||
**错误**:`mvn clean compile` 失败
|
||||
|
||||
**解决**:
|
||||
1. 检查 Java 版本:`java -version`(需要 Java 8 或更高)
|
||||
2. 检查 Maven 版本:`mvn -version`
|
||||
3. 查看错误信息,可能缺少依赖
|
||||
|
||||
### Q2: 端口被占用
|
||||
|
||||
**错误**:`Port 8080 was already in use`
|
||||
|
||||
**解决**:
|
||||
1. 找到占用端口的进程:
|
||||
```batch
|
||||
netstat -ano | findstr 8080
|
||||
```
|
||||
2. 结束进程:
|
||||
```batch
|
||||
taskkill /PID <进程ID> /F
|
||||
```
|
||||
3. 或者修改端口(在 `application.properties` 中)
|
||||
|
||||
### Q3: 前端请求超时
|
||||
|
||||
**错误**:前端显示 `timeout of 10000ms exceeded`
|
||||
|
||||
**原因**:
|
||||
- 后端未运行
|
||||
- 后端处理请求时间过长
|
||||
- 网络问题
|
||||
|
||||
**解决**:
|
||||
1. 确认后端正在运行
|
||||
2. 查看后端日志是否有错误
|
||||
3. 使用模拟模式测试
|
||||
|
||||
### Q4: 看不到详细日志
|
||||
|
||||
**解决**:
|
||||
1. 确认使用 `rebuild_backend_with_logs.bat` 启动
|
||||
2. 或者在 `application.properties` 中添加:
|
||||
```properties
|
||||
logging.level.com.soybean.admin=DEBUG
|
||||
```
|
||||
|
||||
## 验证清单
|
||||
|
||||
- [ ] 后端已停止旧的进程
|
||||
- [ ] 运行了 `rebuild_backend_with_logs.bat`
|
||||
- [ ] 看到后端启动成功的日志
|
||||
- [ ] 端口 8080 正常监听
|
||||
- [ ] 运行了 `test_amt_api.bat` 验证 API
|
||||
- [ ] 前端可以访问
|
||||
- [ ] 点击"测试连接"时后端有日志输出
|
||||
|
||||
## 下一步
|
||||
|
||||
如果完成以上步骤后:
|
||||
|
||||
1. **有日志但连接失败**:
|
||||
- 查看 `AMT_TROUBLESHOOTING.md`
|
||||
- 使用 `quick_amt_test.bat` 诊断网络
|
||||
|
||||
2. **模拟模式正常**:
|
||||
- 说明代码和流程没问题
|
||||
- 专注于解决真实 AMT 连接问题
|
||||
|
||||
3. **仍然没有日志**:
|
||||
- 检查防火墙设置
|
||||
- 检查前端配置
|
||||
- 查看浏览器控制台错误
|
||||
|
||||
## 获取帮助
|
||||
|
||||
如果问题仍未解决:
|
||||
1. 复制完整的错误信息
|
||||
2. 复制后端日志
|
||||
3. 复制浏览器控制台错误
|
||||
4. 说明已尝试的步骤
|
||||
242
AMT_QUICK_START.md
Normal file
242
AMT_QUICK_START.md
Normal file
@ -0,0 +1,242 @@
|
||||
# AMT 设备添加功能 - 快速开始
|
||||
|
||||
## 问题诊断
|
||||
|
||||
### 超时错误:timeout of 10000ms exceeded
|
||||
|
||||
这个错误表示无法连接到 AMT 设备。请按以下步骤排查:
|
||||
|
||||
## 步骤 1:运行快速测试
|
||||
|
||||
运行 `quick_amt_test.bat` 进行基本连接测试:
|
||||
|
||||
```batch
|
||||
quick_amt_test.bat
|
||||
```
|
||||
|
||||
输入 AMT 设备的 IP 地址,查看测试结果。
|
||||
|
||||
### 测试结果分析
|
||||
|
||||
#### 情况 1:Ping 失败
|
||||
**问题**:网络不可达
|
||||
**解决**:
|
||||
- 检查 IP 地址是否正确
|
||||
- 检查网络连接
|
||||
- 确认设备已开机
|
||||
|
||||
#### 情况 2:Ping 成功,但端口关闭
|
||||
**问题**:AMT 未启用或服务未运行
|
||||
**解决**:
|
||||
1. 在 AMT 设备上启用 AMT
|
||||
2. 检查 AMT 服务状态
|
||||
3. 检查防火墙设置
|
||||
|
||||
#### 情况 3:端口开放,但连接超时
|
||||
**问题**:AMT 配置问题或认证失败
|
||||
**解决**:
|
||||
1. 检查 AMT 用户名和密码
|
||||
2. 尝试重启 AMT 服务
|
||||
3. 查看 AMT 配置
|
||||
|
||||
## 步骤 2:使用模拟模式测试功能
|
||||
|
||||
如果暂时没有真实的 AMT 设备,可以使用模拟模式测试功能:
|
||||
|
||||
### 启用模拟模式
|
||||
|
||||
1. **方法 1:修改代码**
|
||||
|
||||
编辑 `backend/src/main/java/com/soybean/admin/controller/DeviceController.java`:
|
||||
|
||||
```java
|
||||
// 将这一行
|
||||
private boolean useMockMode = false;
|
||||
|
||||
// 改为
|
||||
private boolean useMockMode = true;
|
||||
```
|
||||
|
||||
2. **方法 2:使用 API 切换**
|
||||
|
||||
发送 POST 请求到:
|
||||
```
|
||||
POST http://localhost:8080/device/amt/toggleMock
|
||||
```
|
||||
|
||||
### 使用模拟模式
|
||||
|
||||
启用模拟模式后:
|
||||
|
||||
1. 在设备列表点击"新增设备"
|
||||
2. 选择"AMT 自动添加"
|
||||
3. 输入任意 IP 地址(如 192.168.1.100)
|
||||
4. 用户名:`admin`
|
||||
5. 密码:`admin`
|
||||
6. 点击"测试连接"
|
||||
7. 应该会成功并自动填充设备信息
|
||||
|
||||
### 模拟模式说明
|
||||
|
||||
- 模拟模式仅用于测试界面和流程
|
||||
- 不会真正连接到 AMT 设备
|
||||
- 测试账号:admin/admin
|
||||
- 会生成模拟的设备信息
|
||||
|
||||
## 步骤 3:配置真实 AMT 设备
|
||||
|
||||
### 3.1 启用 AMT
|
||||
|
||||
1. **进入 BIOS/UEFI**
|
||||
- 重启设备
|
||||
- 按 F2 或 Del 进入 BIOS
|
||||
|
||||
2. **进入 Intel ME 配置**
|
||||
- 在 BIOS 中找到 Intel ME 或 AMT 选项
|
||||
- 或者在开机时按 Ctrl+P 直接进入 MEBx
|
||||
|
||||
3. **启用 AMT**
|
||||
- Intel(R) ME Configuration
|
||||
- Intel(R) AMT Configuration
|
||||
- Manageability Feature Selection
|
||||
- 选择 "Intel AMT"
|
||||
|
||||
4. **配置网络**
|
||||
- Network Setup
|
||||
- TCP/IP Settings
|
||||
- 选择 DHCP 或配置静态 IP
|
||||
|
||||
5. **设置管理员密码**
|
||||
- MEBx Password
|
||||
- 设置强密码(至少 8 位,包含大小写字母、数字和特殊字符)
|
||||
- 记住这个密码!
|
||||
|
||||
6. **激活 AMT**
|
||||
- Activate Network Access
|
||||
- 选择激活方式(通常选择 "Host Based")
|
||||
|
||||
7. **保存并退出**
|
||||
- 保存设置
|
||||
- 退出并重启
|
||||
|
||||
### 3.2 验证 AMT 配置
|
||||
|
||||
在 Windows 上验证 AMT 是否正常运行:
|
||||
|
||||
```batch
|
||||
# 检查 LMS 服务状态
|
||||
sc query LMS
|
||||
|
||||
# 如果服务未运行,启动它
|
||||
net start LMS
|
||||
|
||||
# 检查端口是否监听
|
||||
netstat -ano | findstr 16992
|
||||
```
|
||||
|
||||
### 3.3 测试 AMT 连接
|
||||
|
||||
使用 PowerShell 测试:
|
||||
|
||||
```powershell
|
||||
# 替换为你的 AMT 设备 IP
|
||||
$amtIP = "192.168.1.100"
|
||||
|
||||
# 测试端口
|
||||
Test-NetConnection -ComputerName $amtIP -Port 16992
|
||||
|
||||
# 如果端口开放,尝试连接
|
||||
$username = "admin"
|
||||
$password = "your_amt_password"
|
||||
$base64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${username}:${password}"))
|
||||
|
||||
$headers = @{
|
||||
"Authorization" = "Basic $base64"
|
||||
"Content-Type" = "application/soap+xml;charset=UTF-8"
|
||||
}
|
||||
|
||||
$body = @"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
|
||||
xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd">
|
||||
<s:Header/>
|
||||
<s:Body>
|
||||
<wsmid:Identify/>
|
||||
</s:Body>
|
||||
</s:Envelope>
|
||||
"@
|
||||
|
||||
try {
|
||||
$response = Invoke-WebRequest -Uri "http://${amtIP}:16992/wsman" -Method POST -Headers $headers -Body $body
|
||||
Write-Host "连接成功!" -ForegroundColor Green
|
||||
Write-Host $response.Content
|
||||
} catch {
|
||||
Write-Host "连接失败:$($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
```
|
||||
|
||||
## 步骤 4:在系统中使用
|
||||
|
||||
### 4.1 保存 AMT 凭证(推荐)
|
||||
|
||||
1. 进入"系统设置" > "AMT 设置"
|
||||
2. 点击"新增凭证"
|
||||
3. 输入凭证名称、用户名和密码
|
||||
4. 保存
|
||||
|
||||
### 4.2 添加 AMT 设备
|
||||
|
||||
1. 进入"设备管理" > "设备列表"
|
||||
2. 点击"新增设备"
|
||||
3. 选择"AMT 自动添加"
|
||||
4. 输入 IP 地址
|
||||
5. 选择认证方式:
|
||||
- 使用已保存凭证:从下拉框选择
|
||||
- 手动输入:填写用户名和密码
|
||||
6. 点击"测试连接"
|
||||
7. 连接成功后,确认设备信息
|
||||
8. 点击"确定"保存
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 超时错误怎么办?
|
||||
**A**: 运行 `quick_amt_test.bat` 诊断网络连接问题。
|
||||
|
||||
### Q2: 401 认证失败怎么办?
|
||||
**A**: 检查用户名和密码是否正确,确认 AMT 已正确配置。
|
||||
|
||||
### Q3: 没有真实 AMT 设备怎么测试?
|
||||
**A**: 启用模拟模式,使用 admin/admin 测试。
|
||||
|
||||
### Q4: 如何知道 AMT 是否已启用?
|
||||
**A**:
|
||||
- 检查 LMS 服务是否运行
|
||||
- 测试端口 16992 是否开放
|
||||
- 尝试访问 http://AMT_IP:16992/wsman
|
||||
|
||||
### Q5: 支持哪些 AMT 版本?
|
||||
**A**: 支持 AMT 6.0 及以上版本。
|
||||
|
||||
## 下一步
|
||||
|
||||
- 查看 `AMT_TROUBLESHOOTING.md` 了解详细的故障排除
|
||||
- 查看 `AMT_DEVICE_ADD_FEATURE.md` 了解完整功能说明
|
||||
- 配置更多 AMT 设备
|
||||
- 探索远程控制功能
|
||||
|
||||
## 获取帮助
|
||||
|
||||
如果遇到问题:
|
||||
1. 查看错误信息
|
||||
2. 运行诊断工具
|
||||
3. 查阅故障排除文档
|
||||
4. 检查 AMT 设备配置
|
||||
5. 查看系统日志
|
||||
|
||||
## 重要提示
|
||||
|
||||
⚠️ **安全警告**:
|
||||
- 使用强密码
|
||||
- 限制网络访问
|
||||
- 定期更新固件
|
||||
- 不要在生产环境使用模拟模式
|
||||
269
AMT_TROUBLESHOOTING.md
Normal file
269
AMT_TROUBLESHOOTING.md
Normal file
@ -0,0 +1,269 @@
|
||||
# AMT 连接故障排除指南
|
||||
|
||||
## 常见错误及解决方案
|
||||
|
||||
### 错误 1: HTTP 401 - 认证失败
|
||||
|
||||
**错误信息**:`AMT 连接测试失败: HTTP 错误: 401`
|
||||
|
||||
**可能原因**:
|
||||
1. 用户名或密码错误
|
||||
2. AMT 未正确配置
|
||||
3. 需要使用 Digest 认证而不是 Basic 认证
|
||||
4. 需要使用 HTTPS 而不是 HTTP
|
||||
|
||||
**解决方案**:
|
||||
|
||||
#### 方案 1:检查 AMT 凭证
|
||||
1. 确认 AMT 管理员用户名(通常是 `admin`)
|
||||
2. 确认 AMT 管理员密码
|
||||
3. 尝试使用 AMT 配置工具重置密码
|
||||
|
||||
#### 方案 2:检查 AMT 配置状态
|
||||
在 AMT 设备上:
|
||||
1. 重启进入 BIOS/UEFI
|
||||
2. 按 Ctrl+P 进入 Intel ME 配置
|
||||
3. 检查 AMT 是否已启用
|
||||
4. 检查网络配置是否正确
|
||||
|
||||
#### 方案 3:使用测试工具诊断
|
||||
运行 `test_amt_connection.bat` 进行详细诊断:
|
||||
```batch
|
||||
test_amt_connection.bat
|
||||
```
|
||||
|
||||
输入 IP 地址和用户名,查看详细的连接测试结果。
|
||||
|
||||
#### 方案 4:手动测试 AMT 连接
|
||||
|
||||
使用 PowerShell 测试:
|
||||
```powershell
|
||||
# 测试端口
|
||||
Test-NetConnection -ComputerName 192.168.1.100 -Port 16992
|
||||
|
||||
# 测试 HTTP 连接
|
||||
$username = "admin"
|
||||
$password = "your_password"
|
||||
$base64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${username}:${password}"))
|
||||
|
||||
$headers = @{
|
||||
"Authorization" = "Basic $base64"
|
||||
"Content-Type" = "application/soap+xml;charset=UTF-8"
|
||||
}
|
||||
|
||||
$body = @"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
|
||||
xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd">
|
||||
<s:Header/>
|
||||
<s:Body>
|
||||
<wsmid:Identify/>
|
||||
</s:Body>
|
||||
</s:Envelope>
|
||||
"@
|
||||
|
||||
Invoke-WebRequest -Uri "http://192.168.1.100:16992/wsman" -Method POST -Headers $headers -Body $body
|
||||
```
|
||||
|
||||
#### 方案 5:尝试 HTTPS 连接
|
||||
|
||||
某些 AMT 配置要求使用 HTTPS:
|
||||
- HTTP 端口:16992
|
||||
- HTTPS 端口:16993
|
||||
|
||||
修改代码已支持自动尝试 HTTPS,重新编译后端即可。
|
||||
|
||||
### 错误 2: 连接超时
|
||||
|
||||
**错误信息**:`AMT 连接超时`
|
||||
|
||||
**可能原因**:
|
||||
1. IP 地址错误
|
||||
2. 网络不可达
|
||||
3. 防火墙阻止
|
||||
4. AMT 未启用
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. **检查网络连接**
|
||||
```batch
|
||||
ping 192.168.1.100
|
||||
```
|
||||
|
||||
2. **检查端口是否开放**
|
||||
```batch
|
||||
telnet 192.168.1.100 16992
|
||||
```
|
||||
或使用 PowerShell:
|
||||
```powershell
|
||||
Test-NetConnection -ComputerName 192.168.1.100 -Port 16992
|
||||
```
|
||||
|
||||
3. **检查防火墙规则**
|
||||
- Windows 防火墙
|
||||
- 网络防火墙
|
||||
- AMT 设备防火墙
|
||||
|
||||
4. **确认 AMT 已启用**
|
||||
- 进入 BIOS/UEFI
|
||||
- 检查 Intel ME 配置
|
||||
- 确认 AMT 服务正在运行
|
||||
|
||||
### 错误 3: 连接被拒绝
|
||||
|
||||
**错误信息**:`Connection refused`
|
||||
|
||||
**可能原因**:
|
||||
1. AMT 服务未运行
|
||||
2. 端口被占用
|
||||
3. AMT 未正确配置
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. **检查 AMT 服务状态**
|
||||
在 AMT 设备上运行:
|
||||
```batch
|
||||
sc query LMS
|
||||
```
|
||||
|
||||
2. **重启 AMT 服务**
|
||||
```batch
|
||||
net stop LMS
|
||||
net start LMS
|
||||
```
|
||||
|
||||
3. **检查端口占用**
|
||||
```batch
|
||||
netstat -ano | findstr 16992
|
||||
```
|
||||
|
||||
## AMT 配置检查清单
|
||||
|
||||
### 基本配置
|
||||
- [ ] AMT 已在 BIOS/UEFI 中启用
|
||||
- [ ] 设置了 AMT 管理员密码
|
||||
- [ ] 配置了网络设置(IP、子网掩码、网关)
|
||||
- [ ] AMT 服务正在运行
|
||||
|
||||
### 网络配置
|
||||
- [ ] AMT 设备网络可达
|
||||
- [ ] 防火墙允许端口 16992 (HTTP) 和 16993 (HTTPS)
|
||||
- [ ] 没有网络隔离或 VLAN 限制
|
||||
|
||||
### 认证配置
|
||||
- [ ] 知道正确的管理员用户名
|
||||
- [ ] 知道正确的管理员密码
|
||||
- [ ] 密码符合复杂度要求
|
||||
|
||||
## 使用 Intel AMT 配置工具
|
||||
|
||||
### Intel ME Configuration Tool (MEBx)
|
||||
|
||||
1. **进入 MEBx**
|
||||
- 开机时按 Ctrl+P
|
||||
- 默认密码:admin
|
||||
|
||||
2. **启用 AMT**
|
||||
- Intel(R) ME Configuration
|
||||
- Intel(R) AMT Configuration
|
||||
- Manageability Feature Selection
|
||||
- 选择 "Intel AMT"
|
||||
|
||||
3. **配置网络**
|
||||
- Network Setup
|
||||
- TCP/IP Settings
|
||||
- 配置 IP 地址(DHCP 或静态)
|
||||
|
||||
4. **设置密码**
|
||||
- MEBx Password
|
||||
- 设置强密码(至少 8 位,包含大小写字母和数字)
|
||||
|
||||
5. **激活 AMT**
|
||||
- Activate Network Access
|
||||
- 选择激活方式
|
||||
|
||||
### Intel Setup and Configuration Service (SCS)
|
||||
|
||||
使用 Intel SCS 进行批量配置:
|
||||
1. 下载 Intel SCS
|
||||
2. 创建配置文件
|
||||
3. 批量部署到设备
|
||||
|
||||
## 常用 AMT 命令
|
||||
|
||||
### 使用 PowerShell 模块
|
||||
|
||||
```powershell
|
||||
# 安装 Intel vPro 模块
|
||||
Install-Module -Name IntelVPro
|
||||
|
||||
# 连接到 AMT 设备
|
||||
$cred = Get-Credential
|
||||
Connect-AMT -ComputerName 192.168.1.100 -Credential $cred
|
||||
|
||||
# 获取设备信息
|
||||
Get-AMTSystemInfo
|
||||
|
||||
# 获取电源状态
|
||||
Get-AMTPowerState
|
||||
|
||||
# 远程开机
|
||||
Invoke-AMTPowerAction -Action PowerOn
|
||||
```
|
||||
|
||||
### 使用 WSMAN 命令行
|
||||
|
||||
```batch
|
||||
# 测试连接
|
||||
wsman identify -r:http://192.168.1.100:16992/wsman -auth:basic -u:admin -p:password
|
||||
|
||||
# 获取系统信息
|
||||
wsman get http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem -r:http://192.168.1.100:16992/wsman -auth:basic -u:admin -p:password
|
||||
```
|
||||
|
||||
## 推荐的 AMT 设置
|
||||
|
||||
### 安全设置
|
||||
- 使用强密码(至少 12 位)
|
||||
- 启用 TLS/SSL
|
||||
- 限制访问 IP 范围
|
||||
- 定期更新固件
|
||||
|
||||
### 网络设置
|
||||
- 使用静态 IP(便于管理)
|
||||
- 配置正确的 DNS
|
||||
- 确保网络稳定
|
||||
|
||||
### 功能设置
|
||||
- 启用远程控制
|
||||
- 启用 KVM(键盘视频鼠标)
|
||||
- 启用 IDE-R(IDE 重定向)
|
||||
- 启用 SOL(串行控制台)
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Intel AMT 官方文档](https://software.intel.com/sites/manageability/)
|
||||
- [Intel vPro 技术指南](https://www.intel.com/content/www/us/en/architecture-and-technology/vpro/vpro-technology-general.html)
|
||||
- [WS-Management 协议规范](https://www.dmtf.org/standards/ws-man)
|
||||
|
||||
## 获取帮助
|
||||
|
||||
如果以上方法都无法解决问题:
|
||||
|
||||
1. 检查 AMT 设备日志
|
||||
2. 查看系统事件日志
|
||||
3. 联系设备制造商支持
|
||||
4. 查阅 Intel AMT 社区论坛
|
||||
|
||||
## 调试模式
|
||||
|
||||
在开发环境中启用详细日志:
|
||||
|
||||
1. 修改 `application.properties`:
|
||||
```properties
|
||||
logging.level.com.soybean.admin.service.AmtService=DEBUG
|
||||
```
|
||||
|
||||
2. 查看详细的请求和响应日志
|
||||
|
||||
3. 使用网络抓包工具(如 Wireshark)分析流量
|
||||
@ -77,6 +77,13 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache HttpClient for Digest Authentication -->
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
<version>5.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@ -4,8 +4,14 @@ import com.soybean.admin.common.Result;
|
||||
import com.soybean.admin.dto.DeviceDTO;
|
||||
import com.soybean.admin.dto.PageRequest;
|
||||
import com.soybean.admin.dto.PageResponse;
|
||||
import com.soybean.admin.dto.AmtTestRequest;
|
||||
import com.soybean.admin.dto.AmtDeviceInfo;
|
||||
import com.soybean.admin.entity.Device;
|
||||
import com.soybean.admin.service.AmtMockService;
|
||||
import com.soybean.admin.service.DeviceService;
|
||||
import com.soybean.admin.service.AmtDigestService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -16,8 +22,19 @@ import java.util.Map;
|
||||
@RequestMapping("/device")
|
||||
public class DeviceController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeviceController.class);
|
||||
|
||||
@Autowired
|
||||
private DeviceService deviceService;
|
||||
|
||||
@Autowired
|
||||
private AmtMockService amtMockService;
|
||||
|
||||
@Autowired
|
||||
private AmtDigestService amtDigestService;
|
||||
|
||||
// 是否使用模拟模式(用于测试)
|
||||
private boolean useMockMode = false; // 改为 true 启用模拟模式
|
||||
|
||||
@PostMapping("/list")
|
||||
public Result<PageResponse<Device>> getDeviceList(@RequestBody PageRequest pageRequest) {
|
||||
@ -90,4 +107,58 @@ public class DeviceController {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/amt/test")
|
||||
public Result<Boolean> testAmtConnection(@RequestBody AmtTestRequest request) {
|
||||
logger.info("收到 AMT 测试连接请求,IP: {}, 模拟模式: {}", request.getIpAddress(), useMockMode);
|
||||
try {
|
||||
boolean success;
|
||||
if (useMockMode) {
|
||||
logger.info("使用模拟模式测试连接");
|
||||
success = amtMockService.mockTestConnection(request);
|
||||
} else {
|
||||
// 使用 Digest 认证
|
||||
logger.info("使用 Digest 认证测试连接");
|
||||
success = amtDigestService.testAmtConnectionWithDigest(request);
|
||||
logger.info("Digest 认证成功");
|
||||
}
|
||||
logger.info("AMT 测试连接结果: {}", success);
|
||||
return Result.success(success);
|
||||
} catch (Exception e) {
|
||||
logger.error("AMT 测试连接失败", e);
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/amt/getInfo")
|
||||
public Result<AmtDeviceInfo> getAmtDeviceInfo(@RequestBody AmtTestRequest request) {
|
||||
logger.info("收到获取 AMT 设备信息请求,IP: {}", request.getIpAddress());
|
||||
try {
|
||||
AmtDeviceInfo deviceInfo;
|
||||
if (useMockMode) {
|
||||
deviceInfo = amtMockService.mockGetDeviceInfo(request);
|
||||
} else {
|
||||
// 使用 Digest 认证
|
||||
logger.info("使用 Digest 认证获取设备信息");
|
||||
deviceInfo = amtDigestService.getAmtDeviceInfoWithDigest(request);
|
||||
}
|
||||
logger.info("成功获取 AMT 设备信息: {}", deviceInfo.getDeviceName());
|
||||
return Result.success(deviceInfo);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取 AMT 设备信息失败", e);
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/amt/toggleMock")
|
||||
public Result<Boolean> toggleMockMode() {
|
||||
useMockMode = !useMockMode;
|
||||
logger.info("切换模拟模式: {}", useMockMode ? "已启用" : "已禁用");
|
||||
return Result.success(useMockMode);
|
||||
}
|
||||
|
||||
@GetMapping("/amt/mockStatus")
|
||||
public Result<Boolean> getMockStatus() {
|
||||
return Result.success(useMockMode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
package com.soybean.admin.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AmtDeviceInfo {
|
||||
private String deviceName;
|
||||
private String deviceCode;
|
||||
private String ipAddress;
|
||||
private String macAddress;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.soybean.admin.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AmtTestRequest {
|
||||
private String ipAddress;
|
||||
private String username;
|
||||
private String password;
|
||||
private Long credentialId; // 可选:使用已保存的凭证ID
|
||||
}
|
||||
@ -0,0 +1,218 @@
|
||||
package com.soybean.admin.service;
|
||||
|
||||
import com.soybean.admin.dto.AmtTestRequest;
|
||||
import com.soybean.admin.dto.AmtDeviceInfo;
|
||||
import com.soybean.admin.entity.AmtCredential;
|
||||
import org.apache.hc.client5.http.auth.AuthScope;
|
||||
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.hc.client5.http.classic.methods.HttpPost;
|
||||
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.HttpHost;
|
||||
import org.apache.hc.core5.http.io.entity.EntityUtils;
|
||||
import org.apache.hc.core5.http.io.entity.StringEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* AMT Digest 认证服务
|
||||
*/
|
||||
@Service
|
||||
public class AmtDigestService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AmtDigestService.class);
|
||||
|
||||
@Autowired
|
||||
private AmtCredentialService amtCredentialService;
|
||||
|
||||
/**
|
||||
* 测试 AMT 连接(使用 Digest 认证)
|
||||
*/
|
||||
public boolean testAmtConnectionWithDigest(AmtTestRequest request) {
|
||||
logger.info("使用 Digest 认证测试 AMT 连接,IP: {}", request.getIpAddress());
|
||||
|
||||
try {
|
||||
String username;
|
||||
String password;
|
||||
|
||||
if (request.getCredentialId() != null) {
|
||||
AmtCredential credential = amtCredentialService.getCredentialById(request.getCredentialId().toString());
|
||||
if (credential == null) {
|
||||
throw new RuntimeException("凭证不存在");
|
||||
}
|
||||
username = credential.getUsername();
|
||||
password = credential.getPassword();
|
||||
} else {
|
||||
username = request.getUsername();
|
||||
password = request.getPassword();
|
||||
}
|
||||
|
||||
logger.info("Digest 认证 - 用户名: {}", username);
|
||||
|
||||
String response = sendDigestRequest(
|
||||
request.getIpAddress(),
|
||||
username,
|
||||
password,
|
||||
getIdentifyRequest()
|
||||
);
|
||||
|
||||
boolean success = response != null && (response.contains("IdentifyResponse") || response.contains("ProductVendor"));
|
||||
logger.info("Digest 认证测试结果: {}", success);
|
||||
|
||||
return success;
|
||||
} catch (Exception e) {
|
||||
logger.error("Digest 认证测试失败", e);
|
||||
throw new RuntimeException("AMT Digest 认证失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 AMT 设备信息(使用 Digest 认证)
|
||||
*/
|
||||
public AmtDeviceInfo getAmtDeviceInfoWithDigest(AmtTestRequest request) {
|
||||
try {
|
||||
String username;
|
||||
String password;
|
||||
|
||||
if (request.getCredentialId() != null) {
|
||||
AmtCredential credential = amtCredentialService.getCredentialById(request.getCredentialId().toString());
|
||||
if (credential == null) {
|
||||
throw new RuntimeException("凭证不存在");
|
||||
}
|
||||
username = credential.getUsername();
|
||||
password = credential.getPassword();
|
||||
} else {
|
||||
username = request.getUsername();
|
||||
password = request.getPassword();
|
||||
}
|
||||
|
||||
AmtDeviceInfo deviceInfo = new AmtDeviceInfo();
|
||||
|
||||
String systemInfo = sendDigestRequest(
|
||||
request.getIpAddress(),
|
||||
username,
|
||||
password,
|
||||
getSystemInfoRequest()
|
||||
);
|
||||
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
Document doc = builder.parse(new ByteArrayInputStream(systemInfo.getBytes()));
|
||||
|
||||
deviceInfo.setIpAddress(request.getIpAddress());
|
||||
deviceInfo.setDeviceName(extractValue(doc, "ElementName"));
|
||||
deviceInfo.setMacAddress("00:00:00:00:00:00"); // 简化处理
|
||||
deviceInfo.setDeviceCode(UUID.randomUUID().toString());
|
||||
|
||||
return deviceInfo;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("获取 AMT 设备信息失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送 Digest 认证请求
|
||||
*/
|
||||
private String sendDigestRequest(String ipAddress, String username, String password, String soapRequest) throws Exception {
|
||||
// 先尝试 HTTP
|
||||
try {
|
||||
return sendDigestRequestWithProtocol("http", ipAddress, 16992, username, password, soapRequest);
|
||||
} catch (Exception e) {
|
||||
logger.warn("HTTP Digest 认证失败,尝试 HTTPS: {}", e.getMessage());
|
||||
// 尝试 HTTPS
|
||||
return sendDigestRequestWithProtocol("https", ipAddress, 16993, username, password, soapRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用指定协议发送 Digest 请求
|
||||
*/
|
||||
private String sendDigestRequestWithProtocol(String protocol, String ipAddress, int port,
|
||||
String username, String password, String soapRequest) throws Exception {
|
||||
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
|
||||
credsProvider.setCredentials(
|
||||
new AuthScope(ipAddress, port),
|
||||
new UsernamePasswordCredentials(username, password.toCharArray())
|
||||
);
|
||||
|
||||
try (CloseableHttpClient httpClient = HttpClients.custom()
|
||||
.setDefaultCredentialsProvider(credsProvider)
|
||||
.build()) {
|
||||
|
||||
HttpHost target = new HttpHost(protocol, ipAddress, port);
|
||||
HttpPost httpPost = new HttpPost("/wsman");
|
||||
httpPost.setHeader("Content-Type", "application/soap+xml;charset=UTF-8");
|
||||
httpPost.setEntity(new StringEntity(soapRequest));
|
||||
|
||||
logger.info("发送 Digest 请求到: {}://{}:{}/wsman", protocol, ipAddress, port);
|
||||
|
||||
try (CloseableHttpResponse response = httpClient.execute(target, httpPost)) {
|
||||
int statusCode = response.getCode();
|
||||
logger.info("收到响应,状态码: {}", statusCode);
|
||||
|
||||
if (statusCode == 401) {
|
||||
throw new RuntimeException("Digest 认证失败 (401)");
|
||||
} else if (statusCode != 200) {
|
||||
throw new RuntimeException("HTTP 错误: " + statusCode);
|
||||
}
|
||||
|
||||
String responseBody = EntityUtils.toString(response.getEntity());
|
||||
logger.info("响应长度: {} 字节", responseBody.length());
|
||||
return responseBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getIdentifyRequest() {
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" " +
|
||||
"xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\">" +
|
||||
"<s:Header/>" +
|
||||
"<s:Body>" +
|
||||
"<wsmid:Identify/>" +
|
||||
"</s:Body>" +
|
||||
"</s:Envelope>";
|
||||
}
|
||||
|
||||
private String getSystemInfoRequest() {
|
||||
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" " +
|
||||
"xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" " +
|
||||
"xmlns:wsman=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\">" +
|
||||
"<s:Header>" +
|
||||
"<wsa:Action s:mustUnderstand=\"true\">http://schemas.xmlsoap.org/ws/2004/09/transfer/Get</wsa:Action>" +
|
||||
"<wsa:To s:mustUnderstand=\"true\">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>" +
|
||||
"<wsman:ResourceURI s:mustUnderstand=\"true\">http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ComputerSystem</wsman:ResourceURI>" +
|
||||
"<wsa:MessageID s:mustUnderstand=\"true\">uuid:" + UUID.randomUUID().toString() + "</wsa:MessageID>" +
|
||||
"<wsa:ReplyTo>" +
|
||||
"<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>" +
|
||||
"</wsa:ReplyTo>" +
|
||||
"</s:Header>" +
|
||||
"<s:Body/>" +
|
||||
"</s:Envelope>";
|
||||
}
|
||||
|
||||
private String extractValue(Document doc, String tagName) {
|
||||
try {
|
||||
NodeList nodeList = doc.getElementsByTagName(tagName);
|
||||
if (nodeList.getLength() > 0) {
|
||||
return nodeList.item(0).getTextContent();
|
||||
}
|
||||
return "Unknown";
|
||||
} catch (Exception e) {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package com.soybean.admin.service;
|
||||
|
||||
import com.soybean.admin.dto.AmtTestRequest;
|
||||
import com.soybean.admin.dto.AmtDeviceInfo;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* AMT 模拟服务 - 用于测试和演示
|
||||
* 当没有真实 AMT 设备时使用
|
||||
*/
|
||||
@Service
|
||||
public class AmtMockService {
|
||||
|
||||
/**
|
||||
* 模拟测试 AMT 连接
|
||||
*/
|
||||
public boolean mockTestConnection(AmtTestRequest request) {
|
||||
// 模拟延迟
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
// 模拟成功(用户名为 admin 且密码为 admin 时成功)
|
||||
if ("admin".equals(request.getUsername()) && "admin".equals(request.getPassword())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new RuntimeException("模拟认证失败:用户名或密码错误(测试账号: admin/admin)");
|
||||
}
|
||||
|
||||
/**
|
||||
* 模拟获取 AMT 设备信息
|
||||
*/
|
||||
public AmtDeviceInfo mockGetDeviceInfo(AmtTestRequest request) {
|
||||
// 模拟延迟
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
AmtDeviceInfo deviceInfo = new AmtDeviceInfo();
|
||||
deviceInfo.setIpAddress(request.getIpAddress());
|
||||
deviceInfo.setDeviceName("Mock-AMT-Device-" + request.getIpAddress().replace(".", "-"));
|
||||
deviceInfo.setDeviceCode(UUID.randomUUID().toString());
|
||||
deviceInfo.setMacAddress(generateMockMacAddress(request.getIpAddress()));
|
||||
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 IP 地址生成模拟 MAC 地址
|
||||
*/
|
||||
private String generateMockMacAddress(String ipAddress) {
|
||||
String[] parts = ipAddress.split("\\.");
|
||||
if (parts.length == 4) {
|
||||
return String.format("00:11:22:%02X:%02X:%02X",
|
||||
Integer.parseInt(parts[1]) % 256,
|
||||
Integer.parseInt(parts[2]) % 256,
|
||||
Integer.parseInt(parts[3]) % 256);
|
||||
}
|
||||
return "00:11:22:33:44:55";
|
||||
}
|
||||
}
|
||||
48
enable_amt_mock_mode.bat
Normal file
48
enable_amt_mock_mode.bat
Normal file
@ -0,0 +1,48 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo 启用 AMT 模拟模式
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 此脚本将:
|
||||
echo 1. 修改代码启用模拟模式
|
||||
echo 2. 重新编译后端
|
||||
echo 3. 启动后端服务
|
||||
echo.
|
||||
echo 模拟模式说明:
|
||||
echo - 不需要真实的 AMT 设备
|
||||
echo - 测试账号:admin / admin
|
||||
echo - 用于测试界面和流程
|
||||
echo.
|
||||
pause
|
||||
|
||||
cd backend\src\main\java\com\soybean\admin\controller
|
||||
|
||||
echo.
|
||||
echo [1/3] 修改 DeviceController.java...
|
||||
|
||||
powershell -Command "(Get-Content DeviceController.java) -replace 'private boolean useMockMode = false;', 'private boolean useMockMode = true;' | Set-Content DeviceController.java"
|
||||
|
||||
echo 已启用模拟模式
|
||||
|
||||
cd ..\..\..\..\..\..
|
||||
|
||||
echo.
|
||||
echo [2/3] 重新编译...
|
||||
call mvn clean compile
|
||||
|
||||
echo.
|
||||
echo [3/3] 启动后端...
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 模拟模式已启用
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 测试账号:
|
||||
echo 用户名:admin
|
||||
echo 密码:admin
|
||||
echo.
|
||||
echo 可以使用任意 IP 地址进行测试
|
||||
echo.
|
||||
call mvn spring-boot:run
|
||||
|
||||
pause
|
||||
41
quick_amt_test.bat
Normal file
41
quick_amt_test.bat
Normal file
@ -0,0 +1,41 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo 快速 AMT 连接测试
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
set /p AMT_IP="请输入 AMT 设备 IP 地址: "
|
||||
|
||||
echo.
|
||||
echo [测试 1] Ping 测试...
|
||||
ping -n 4 %AMT_IP%
|
||||
|
||||
echo.
|
||||
echo [测试 2] 端口 16992 (HTTP) 测试...
|
||||
powershell -Command "$result = Test-NetConnection -ComputerName %AMT_IP% -Port 16992 -WarningAction SilentlyContinue; if($result.TcpTestSucceeded) { Write-Host '端口 16992 开放 - 成功' -ForegroundColor Green } else { Write-Host '端口 16992 关闭 - 失败' -ForegroundColor Red }"
|
||||
|
||||
echo.
|
||||
echo [测试 3] 端口 16993 (HTTPS) 测试...
|
||||
powershell -Command "$result = Test-NetConnection -ComputerName %AMT_IP% -Port 16993 -WarningAction SilentlyContinue; if($result.TcpTestSucceeded) { Write-Host '端口 16993 开放 - 成功' -ForegroundColor Green } else { Write-Host '端口 16993 关闭 - 失败' -ForegroundColor Red }"
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 诊断结果
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 如果 Ping 失败:
|
||||
echo - 检查 IP 地址是否正确
|
||||
echo - 检查网络连接
|
||||
echo - 检查防火墙设置
|
||||
echo.
|
||||
echo 如果端口关闭:
|
||||
echo - AMT 可能未启用
|
||||
echo - 防火墙阻止了端口
|
||||
echo - AMT 服务未运行
|
||||
echo.
|
||||
echo 如果端口开放但仍然超时:
|
||||
echo - 检查 AMT 用户名和密码
|
||||
echo - 尝试在 AMT 设备上重启 LMS 服务
|
||||
echo.
|
||||
|
||||
pause
|
||||
22
rebuild_and_test_amt.bat
Normal file
22
rebuild_and_test_amt.bat
Normal file
@ -0,0 +1,22 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo 重新编译后端并测试 AMT 功能
|
||||
echo ========================================
|
||||
|
||||
cd backend
|
||||
|
||||
echo.
|
||||
echo [1/3] 清理旧的编译文件...
|
||||
call mvn clean
|
||||
|
||||
echo.
|
||||
echo [2/3] 编译项目...
|
||||
call mvn compile
|
||||
|
||||
echo.
|
||||
echo [3/3] 启动后端服务...
|
||||
echo 提示:后端将在 http://localhost:8080 启动
|
||||
echo.
|
||||
call mvn spring-boot:run
|
||||
|
||||
pause
|
||||
40
rebuild_backend_with_logs.bat
Normal file
40
rebuild_backend_with_logs.bat
Normal file
@ -0,0 +1,40 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo 重新编译后端并启动(带详细日志)
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
cd backend
|
||||
|
||||
echo [1/2] 清理并重新编译...
|
||||
call mvn clean compile
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo.
|
||||
echo 编译失败!请检查错误信息。
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [2/2] 启动后端服务(带详细日志)...
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 后端服务启动中...
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 日志级别:DEBUG
|
||||
echo 端口:8080
|
||||
echo.
|
||||
echo 提示:
|
||||
echo - 查看控制台输出了解详细日志
|
||||
echo - AMT 测试连接时会显示详细的连接过程
|
||||
echo - 按 Ctrl+C 停止服务
|
||||
echo.
|
||||
|
||||
REM 设置日志级别为 DEBUG
|
||||
set JAVA_OPTS=-Dlogging.level.com.soybean.admin=DEBUG
|
||||
|
||||
call mvn spring-boot:run
|
||||
|
||||
pause
|
||||
33
rebuild_digest_only.bat
Normal file
33
rebuild_digest_only.bat
Normal file
@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo 重新编译后端(仅 Digest 认证)
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
cd backend
|
||||
|
||||
echo 清理旧的编译文件...
|
||||
call mvn clean
|
||||
|
||||
echo.
|
||||
echo 重新编译项目...
|
||||
call mvn compile
|
||||
|
||||
echo.
|
||||
echo 打包项目...
|
||||
call mvn package -DskipTests
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 编译完成!
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 现在可以启动后端服务:
|
||||
echo cd backend
|
||||
echo java -jar target/soybean-admin-0.0.1-SNAPSHOT.jar
|
||||
echo.
|
||||
echo 或者运行:
|
||||
echo start_backend.bat
|
||||
echo.
|
||||
|
||||
pause
|
||||
42
rebuild_with_digest_auth.bat
Normal file
42
rebuild_with_digest_auth.bat
Normal file
@ -0,0 +1,42 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo 重新编译后端(添加 Digest 认证支持)
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
cd backend
|
||||
|
||||
echo [1/3] 清理旧的编译文件...
|
||||
call mvn clean
|
||||
|
||||
echo.
|
||||
echo [2/3] 下载依赖并编译...
|
||||
echo 注意:首次运行会下载 Apache HttpClient 依赖
|
||||
call mvn compile
|
||||
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo.
|
||||
echo 编译失败!请检查错误信息。
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [3/3] 启动后端服务...
|
||||
echo.
|
||||
echo ========================================
|
||||
echo Digest 认证支持已添加
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 现在支持两种认证方式:
|
||||
echo 1. Basic 认证(先尝试)
|
||||
echo 2. Digest 认证(Basic 失败后自动尝试)
|
||||
echo.
|
||||
echo 提示:
|
||||
echo - 系统会自动尝试两种认证方式
|
||||
echo - 查看日志了解使用了哪种认证
|
||||
echo.
|
||||
|
||||
call mvn spring-boot:run
|
||||
|
||||
pause
|
||||
@ -75,3 +75,25 @@ export function fetchDeviceStatistics() {
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 AMT 连接
|
||||
*/
|
||||
export function fetchTestAmtConnection(data: Api.Device.AmtTestRequest) {
|
||||
return request<boolean>({
|
||||
url: '/device/amt/test',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 AMT 设备信息
|
||||
*/
|
||||
export function fetchAmtDeviceInfo(data: Api.Device.AmtTestRequest) {
|
||||
return request<Api.Device.AmtDeviceInfo>({
|
||||
url: '/device/amt/getInfo',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
24
src/typings/api/device.d.ts
vendored
24
src/typings/api/device.d.ts
vendored
@ -51,5 +51,29 @@ declare namespace Api {
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/** AMT 测试请求 */
|
||||
interface AmtTestRequest {
|
||||
/** IP地址 */
|
||||
ipAddress: string;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
/** 密码 */
|
||||
password?: string;
|
||||
/** 凭证ID */
|
||||
credentialId?: number;
|
||||
}
|
||||
|
||||
/** AMT 设备信息 */
|
||||
interface AmtDeviceInfo {
|
||||
/** 设备名称 */
|
||||
deviceName: string;
|
||||
/** 设备编号 */
|
||||
deviceCode: string;
|
||||
/** IP地址 */
|
||||
ipAddress: string;
|
||||
/** MAC地址 */
|
||||
macAddress: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
src/typings/components.d.ts
vendored
2
src/typings/components.d.ts
vendored
@ -49,6 +49,7 @@ declare module 'vue' {
|
||||
IconMdiIp: typeof import('~icons/mdi/ip')['default']
|
||||
IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||
IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||
IconMdiLanConnect: typeof import('~icons/mdi/lan-connect')['default']
|
||||
IconMdiMagnify: typeof import('~icons/mdi/magnify')['default']
|
||||
IconMdiMapMarker: typeof import('~icons/mdi/map-marker')['default']
|
||||
IconMdiMemory: typeof import('~icons/mdi/memory')['default']
|
||||
@ -188,6 +189,7 @@ declare global {
|
||||
const IconMdiIp: typeof import('~icons/mdi/ip')['default']
|
||||
const IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
|
||||
const IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
|
||||
const IconMdiLanConnect: typeof import('~icons/mdi/lan-connect')['default']
|
||||
const IconMdiMagnify: typeof import('~icons/mdi/magnify')['default']
|
||||
const IconMdiMapMarker: typeof import('~icons/mdi/map-marker')['default']
|
||||
const IconMdiMemory: typeof import('~icons/mdi/memory')['default']
|
||||
|
||||
@ -93,8 +93,88 @@
|
||||
v-model:show="modalVisible"
|
||||
:title="modalTitle"
|
||||
preset="card"
|
||||
class="w-700px"
|
||||
class="w-800px"
|
||||
>
|
||||
<!-- 添加方式选择(仅新增时显示) -->
|
||||
<n-radio-group v-if="!isEdit" v-model:value="addMode" class="mb-16px">
|
||||
<n-space>
|
||||
<n-radio value="manual">手动添加</n-radio>
|
||||
<n-radio value="amt">AMT 自动添加</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
|
||||
<!-- AMT 添加方式 -->
|
||||
<div v-if="!isEdit && addMode === 'amt'" class="mb-16px">
|
||||
<n-card title="AMT 设备发现" size="small" :bordered="false" class="bg-gray-50">
|
||||
<n-form label-placement="left" label-width="100px">
|
||||
<n-form-item label="IP 地址" required>
|
||||
<n-input
|
||||
v-model:value="amtFormData.ipAddress"
|
||||
placeholder="请输入 AMT 设备 IP 地址"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="认证方式">
|
||||
<n-switch
|
||||
v-model:value="amtFormData.useCredential"
|
||||
@update:value="handleCredentialToggle"
|
||||
>
|
||||
<template #checked>使用已保存凭证</template>
|
||||
<template #unchecked>手动输入</template>
|
||||
</n-switch>
|
||||
</n-form-item>
|
||||
|
||||
<template v-if="amtFormData.useCredential">
|
||||
<n-form-item label="选择凭证" required>
|
||||
<n-select
|
||||
v-model:value="amtFormData.credentialId"
|
||||
:options="amtCredentials.map(c => ({ label: c.credentialName, value: c.credentialId }))"
|
||||
placeholder="请选择 AMT 凭证"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<n-form-item label="用户名" required>
|
||||
<n-input
|
||||
v-model:value="amtFormData.username"
|
||||
placeholder="请输入 AMT 用户名"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="密码" required>
|
||||
<n-input
|
||||
v-model:value="amtFormData.password"
|
||||
type="password"
|
||||
show-password-on="click"
|
||||
placeholder="请输入 AMT 密码"
|
||||
/>
|
||||
</n-form-item>
|
||||
</template>
|
||||
|
||||
<n-form-item>
|
||||
<n-space>
|
||||
<n-button
|
||||
type="primary"
|
||||
:loading="amtTesting"
|
||||
@click="handleTestAmtConnection"
|
||||
>
|
||||
<icon-mdi-lan-connect class="mr-4px" />
|
||||
测试连接
|
||||
</n-button>
|
||||
<n-tag v-if="amtTestSuccess" type="success">
|
||||
<icon-mdi-check-circle class="mr-4px" />
|
||||
连接成功
|
||||
</n-tag>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-divider class="!my-16px">设备信息</n-divider>
|
||||
</div>
|
||||
|
||||
<!-- 设备信息表单 -->
|
||||
<n-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
@ -107,25 +187,28 @@
|
||||
<n-input
|
||||
v-model:value="formData.deviceName"
|
||||
placeholder="请输入设备名称"
|
||||
:disabled="!isEdit && addMode === 'amt' && !amtTestSuccess"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi label="UUID" path="deviceCode">
|
||||
<n-input
|
||||
v-model:value="formData.deviceCode"
|
||||
placeholder="请输入UUID"
|
||||
:disabled="isEdit"
|
||||
:disabled="isEdit || (addMode === 'amt' && !amtTestSuccess)"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi label="IP地址" path="ipAddress">
|
||||
<n-input
|
||||
v-model:value="formData.ipAddress"
|
||||
placeholder="请输入IP地址"
|
||||
:disabled="!isEdit && addMode === 'amt' && !amtTestSuccess"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi label="MAC地址" path="macAddress">
|
||||
<n-input
|
||||
v-model:value="formData.macAddress"
|
||||
placeholder="请输入MAC地址"
|
||||
:disabled="!isEdit && addMode === 'amt' && !amtTestSuccess"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi label="设备状态" path="status">
|
||||
@ -148,7 +231,14 @@
|
||||
<template #footer>
|
||||
<n-space justify="end">
|
||||
<n-button @click="modalVisible = false">取消</n-button>
|
||||
<n-button type="primary" @click="handleSubmit" :loading="submitLoading">确定</n-button>
|
||||
<n-button
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
:loading="submitLoading"
|
||||
:disabled="!isEdit && addMode === 'amt' && !amtTestSuccess"
|
||||
>
|
||||
确定
|
||||
</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
@ -187,8 +277,11 @@ import {
|
||||
fetchCreateDevice,
|
||||
fetchUpdateDevice,
|
||||
fetchDeleteDevice,
|
||||
fetchBatchDeleteDevice
|
||||
fetchBatchDeleteDevice,
|
||||
fetchTestAmtConnection,
|
||||
fetchAmtDeviceInfo
|
||||
} from '@/service/api/device';
|
||||
import { fetchAllActiveCredentials, type AmtCredential } from '@/service/api/amt';
|
||||
|
||||
defineOptions({
|
||||
name: 'DeviceList'
|
||||
@ -353,6 +446,22 @@ const modalTitle = ref('');
|
||||
const isEdit = ref(false);
|
||||
const submitLoading = ref(false);
|
||||
const formRef = ref();
|
||||
|
||||
// 添加方式:manual(手动)、amt(AMT自动)
|
||||
const addMode = ref<'manual' | 'amt'>('manual');
|
||||
|
||||
// AMT 相关
|
||||
const amtFormData = reactive({
|
||||
ipAddress: '',
|
||||
username: '',
|
||||
password: '',
|
||||
credentialId: null as number | null,
|
||||
useCredential: false
|
||||
});
|
||||
const amtCredentials = ref<AmtCredential[]>([]);
|
||||
const amtTesting = ref(false);
|
||||
const amtTestSuccess = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
id: null as number | null,
|
||||
deviceName: '',
|
||||
@ -421,6 +530,8 @@ function handleCheck(keys: number[]) {
|
||||
function handleAdd() {
|
||||
isEdit.value = false;
|
||||
modalTitle.value = '新增设备';
|
||||
addMode.value = 'manual';
|
||||
amtTestSuccess.value = false;
|
||||
Object.assign(formData, {
|
||||
id: null,
|
||||
deviceName: '',
|
||||
@ -430,7 +541,15 @@ function handleAdd() {
|
||||
macAddress: '',
|
||||
remark: ''
|
||||
});
|
||||
Object.assign(amtFormData, {
|
||||
ipAddress: '',
|
||||
username: '',
|
||||
password: '',
|
||||
credentialId: null,
|
||||
useCredential: false
|
||||
});
|
||||
modalVisible.value = true;
|
||||
loadAmtCredentials();
|
||||
}
|
||||
|
||||
// 编辑
|
||||
@ -506,4 +625,105 @@ async function handleBatchDelete() {
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
// 加载 AMT 凭证列表
|
||||
async function loadAmtCredentials() {
|
||||
try {
|
||||
const { data } = await fetchAllActiveCredentials();
|
||||
amtCredentials.value = data || [];
|
||||
} catch (error) {
|
||||
console.error('加载 AMT 凭证失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 测试 AMT 连接
|
||||
async function handleTestAmtConnection() {
|
||||
// 验证必填项
|
||||
if (!amtFormData.ipAddress) {
|
||||
window.$message?.warning('请输入 IP 地址');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!amtFormData.useCredential && (!amtFormData.username || !amtFormData.password)) {
|
||||
window.$message?.warning('请输入用户名和密码,或选择已保存的凭证');
|
||||
return;
|
||||
}
|
||||
|
||||
if (amtFormData.useCredential && !amtFormData.credentialId) {
|
||||
window.$message?.warning('请选择 AMT 凭证');
|
||||
return;
|
||||
}
|
||||
|
||||
amtTesting.value = true;
|
||||
amtTestSuccess.value = false;
|
||||
|
||||
try {
|
||||
const requestData: Api.Device.AmtTestRequest = {
|
||||
ipAddress: amtFormData.ipAddress
|
||||
};
|
||||
|
||||
if (amtFormData.useCredential && amtFormData.credentialId) {
|
||||
requestData.credentialId = amtFormData.credentialId;
|
||||
} else {
|
||||
requestData.username = amtFormData.username;
|
||||
requestData.password = amtFormData.password;
|
||||
}
|
||||
|
||||
const { data } = await fetchTestAmtConnection(requestData);
|
||||
|
||||
if (data) {
|
||||
amtTestSuccess.value = true;
|
||||
window.$message?.success('AMT 连接测试成功');
|
||||
|
||||
// 自动获取设备信息
|
||||
await handleGetAmtDeviceInfo();
|
||||
} else {
|
||||
window.$message?.error('AMT 连接测试失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
window.$message?.error(error?.message || 'AMT 连接测试失败');
|
||||
} finally {
|
||||
amtTesting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取 AMT 设备信息
|
||||
async function handleGetAmtDeviceInfo() {
|
||||
try {
|
||||
const requestData: Api.Device.AmtTestRequest = {
|
||||
ipAddress: amtFormData.ipAddress
|
||||
};
|
||||
|
||||
if (amtFormData.useCredential && amtFormData.credentialId) {
|
||||
requestData.credentialId = amtFormData.credentialId;
|
||||
} else {
|
||||
requestData.username = amtFormData.username;
|
||||
requestData.password = amtFormData.password;
|
||||
}
|
||||
|
||||
const { data } = await fetchAmtDeviceInfo(requestData);
|
||||
|
||||
// 填充表单数据
|
||||
formData.deviceName = data.deviceName;
|
||||
formData.deviceCode = data.deviceCode;
|
||||
formData.ipAddress = data.ipAddress;
|
||||
formData.macAddress = data.macAddress;
|
||||
|
||||
window.$message?.success('设备信息获取成功');
|
||||
} catch (error: any) {
|
||||
window.$message?.error(error?.message || '获取设备信息失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 切换凭证使用方式
|
||||
function handleCredentialToggle(value: boolean) {
|
||||
if (value) {
|
||||
amtFormData.username = '';
|
||||
amtFormData.password = '';
|
||||
} else {
|
||||
amtFormData.credentialId = null;
|
||||
}
|
||||
amtTestSuccess.value = false;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@ -1,16 +1,43 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo ========================================
|
||||
echo 测试 AMT API 接口
|
||||
echo 测试 AMT API 是否正常
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
echo 测试获取凭证列表...
|
||||
curl -X GET "http://localhost:8080/api/amt/credential/list?page=1&size=10" -H "Content-Type: application/json"
|
||||
echo [测试 1] 检查后端是否运行...
|
||||
curl -s http://localhost:8080/device/statistics >nul 2>&1
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
echo 后端未运行或无法连接!
|
||||
echo 请先启动后端服务。
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo 后端正常运行 ✓
|
||||
|
||||
echo.
|
||||
echo [测试 2] 检查模拟模式状态...
|
||||
curl -s http://localhost:8080/device/amt/mockStatus
|
||||
echo.
|
||||
|
||||
echo.
|
||||
echo [测试 3] 测试 AMT 连接 API(使用模拟数据)...
|
||||
echo.
|
||||
echo 发送测试请求...
|
||||
curl -X POST http://localhost:8080/device/amt/test ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"ipAddress\":\"192.168.1.100\",\"username\":\"admin\",\"password\":\"admin\"}"
|
||||
|
||||
echo.
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 测试完成
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 如果看到成功响应,说明 API 正常工作。
|
||||
echo 如果看到错误,请检查:
|
||||
echo 1. 后端是否正常启动
|
||||
echo 2. 端口 8080 是否被占用
|
||||
echo 3. 查看后端控制台日志
|
||||
echo.
|
||||
|
||||
pause
|
||||
|
||||
43
test_amt_connection.bat
Normal file
43
test_amt_connection.bat
Normal file
@ -0,0 +1,43 @@
|
||||
@echo off
|
||||
echo ========================================
|
||||
echo AMT 连接测试工具
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
set /p AMT_IP="请输入 AMT 设备 IP 地址: "
|
||||
set /p AMT_USER="请输入 AMT 用户名 (默认: admin): "
|
||||
if "%AMT_USER%"=="" set AMT_USER=admin
|
||||
|
||||
echo.
|
||||
echo 正在测试连接到 %AMT_IP%...
|
||||
echo.
|
||||
|
||||
REM 测试端口 16992 是否开放
|
||||
echo [1/4] 测试端口 16992 (HTTP)...
|
||||
powershell -Command "Test-NetConnection -ComputerName %AMT_IP% -Port 16992 -InformationLevel Detailed"
|
||||
|
||||
echo.
|
||||
echo [2/4] 测试端口 16993 (HTTPS)...
|
||||
powershell -Command "Test-NetConnection -ComputerName %AMT_IP% -Port 16993 -InformationLevel Detailed"
|
||||
|
||||
echo.
|
||||
echo [3/4] 尝试 HTTP 连接...
|
||||
curl -v -u %AMT_USER% http://%AMT_IP%:16992/wsman -H "Content-Type: application/soap+xml;charset=UTF-8" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\"><s:Header/><s:Body><wsmid:Identify/></s:Body></s:Envelope>"
|
||||
|
||||
echo.
|
||||
echo [4/4] 尝试 HTTPS 连接...
|
||||
curl -v -k -u %AMT_USER% https://%AMT_IP%:16993/wsman -H "Content-Type: application/soap+xml;charset=UTF-8" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsmid=\"http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd\"><s:Header/><s:Body><wsmid:Identify/></s:Body></s:Envelope>"
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 测试完成
|
||||
echo ========================================
|
||||
echo.
|
||||
echo 提示:
|
||||
echo - 如果端口不通,请检查防火墙设置
|
||||
echo - 如果返回 401,请检查用户名和密码
|
||||
echo - 如果返回 404,AMT 可能未启用
|
||||
echo - HTTP 端口: 16992, HTTPS 端口: 16993
|
||||
echo.
|
||||
|
||||
pause
|
||||
Loading…
x
Reference in New Issue
Block a user