# 授权文件功能演示说明 ## 📸 功能界面说明 由于这是文本环境,以下用文字描述各功能的界面和操作流程。 ## 1. 授权管理主页面 **访问路径**: http://localhost:3000/licenses ### 页面布局 ``` ┌─────────────────────────────────────────────────────────────┐ │ ← 授权管理 [导出] [选择授权项] │ │ 管理设备授权许可 │ ├─────────────────────────────────────────────────────────────┤ │ ℹ️ 每个设备型号对应一套授权模块配置... │ ├─────────────────────────────────────────────────────────────┤ │ 筛选条件: [设备型号▼] [查询] │ ├─────────────────────────────────────────────────────────────┤ │ 设备型号 | 授权模块 | 操作 │ │ GD-30 | [一维] [二维] [三维] | [预览] [下载] [编辑] │ │ GD-20 | [一维] [二维] | [预览] [下载] [编辑] │ ├─────────────────────────────────────────────────────────────┤ │ 共 2 条 [<] [1] [2] [>] │ └─────────────────────────────────────────────────────────────┘ ``` ### 操作按钮说明 - **预览** 👁️ - 点击后弹出JSON预览窗口 - **下载** 📄 - 直接下载JSON文件到本地 - **编辑** ✏️ - 修改授权配置 ## 2. 授权文件预览弹窗 ### 触发方式 点击列表中的"预览"按钮 ### 弹窗内容 ``` ┌──────────────────────────────────────────────────────────┐ │ 授权文件预览 - GD-30 [X] │ ├──────────────────────────────────────────────────────────┤ │ { │ │ "version": "1.0", │ │ "generatedAt": "2026-04-30T16:00:00.000Z", │ │ "deviceModel": "GD-30 Supreme", │ │ "deviceSN": "", │ │ "validUntil": "2027-04-30", │ │ "status": "active", │ │ "authModules": [ │ │ { │ │ "id": "1D", │ │ "name": "一维自电/电阻率/激电测试模块", │ │ "category": "一维", │ │ "enabled": true │ │ }, │ │ ... │ │ ], │ │ "config": { │ │ "name": "CFG-GD30-v2.1", │ │ "emissionParams": {...}, │ │ "acquisitionParams": {...} │ │ }, │ │ "signature": { │ │ "algorithm": "SHA256", │ │ "value": "a1b2c3d4...", │ │ "publicKey": "platform-public-key-placeholder" │ │ } │ │ } │ ├──────────────────────────────────────────────────────────┤ │ [下载JSON] [关闭] │ └──────────────────────────────────────────────────────────┘ ``` ### 功能特点 - JSON格式化显示,带语法高亮 - 可滚动查看完整内容 - 支持一键下载JSON文件 - 点击背景或关闭按钮退出 ## 3. 创建/编辑授权抽屉 ### 触发方式 点击"选择授权项"按钮 ### 抽屉内容 ``` ┌──────────────────────────────────────┐ │ 选择授权项 [X] │ ├──────────────────────────────────────┤ │ 设备型号 │ │ [GD-30 Supreme ▼] │ │ │ │ 授权项目 [全选] [清空]│ │ ┌──────────────────────────────────┐ │ │ │ ☑ 分类 │ 名称 │ 说明 │ │ │ ├──────────────────────────────────┤ │ │ │ ☑ 一维 │ 一维自电... │ ... │ │ │ │ ☑ 二维 │ 二维自电... │ ... │ │ │ │ ☑ 三维 │ 三维自电... │ ... │ │ │ │ □ 水上 │ 水上... │ ... │ │ │ │ □ 跨孔 │ 跨孔... │ ... │ │ │ │ □ 电流场法│ 电流场法... │ ... │ │ │ └──────────────────────────────────┘ │ │ │ │ 已选择 3 项 │ │ │ │ ℹ️ 授权文件由选定的授权项与对应型号的 │ │ 配置文件共同生成... │ │ │ │ [保存] │ └──────────────────────────────────────┘ ``` ### 交互说明 - 点击行可选中/取消选中 - 支持全选/清空快捷操作 - 保存时自动生成JSON授权文件 ## 4. 手机APP调用流程演示 ### 场景:设备启动时获取授权 #### Step 1: APP发起请求 ```javascript GET /api/licenses/download?sn=GD30-20260430-001 ``` #### Step 2: 平台处理流程 ``` 接收请求 ↓ 验证设备SN是否存在 ↓ 查找设备级授权 (device_sn匹配) ↓ 未找到 查找型号级授权 (model匹配 + 状态生效 + 未过期) ↓ 获取关联的配置文件 ↓ 生成/读取授权文件JSON ↓ 记录下载日志 (时间、IP、APP版本) ↓ 返回JSON响应 ``` #### Step 3: APP接收响应 ```json { "version": "1.0", "deviceModel": "GD-30 Supreme", "deviceSN": "GD30-20260430-001", "validUntil": "2027-04-30", "status": "active", "authModules": [ {"id": "1D", "name": "...", "enabled": true}, {"id": "2D", "name": "...", "enabled": true}, {"id": "3D", "name": "...", "enabled": true} ], "config": { "emissionParams": {"maxVoltage": "1000V", ...}, "acquisitionParams": {"channels": 12, ...} }, "signature": {...} } ``` #### Step 4: APP处理授权 ```javascript // 1. 验证签名 if (!verifySignature(license)) { throw new Error('授权文件被篡改'); } // 2. 检查有效期 if (new Date(license.validUntil) < new Date()) { throw new Error('授权已过期'); } // 3. 启用功能模块 license.authModules.forEach(module => { if (module.enabled) { app.enableFeature(module.id); } }); // 4. 应用配置参数 app.applyConfig(license.config); // 5. 显示授权信息 console.log(`授权有效期至: ${license.validUntil}`); ``` ## 5. 数据库查询演示 ### 查看授权记录 ```sql SELECT id, model, modules, expiry, status, CASE WHEN license_file IS NOT NULL THEN '已生成' ELSE '未生成' END as file_status FROM licenses ORDER BY id DESC; ``` **示例输出:** ``` id | model | modules | expiry | status | file_status 1 | GD-30 | 一维, 二维, 三维| 2027-04-30 | 生效 | 已生成 2 | GD-20 | 一维, 二维 | 2027-04-30 | 生效 | 已生成 ``` ### 查看下载日志 ```sql SELECT l.device_sn, l.download_time, l.ip_address, lic.model, lic.expiry FROM license_download_logs l JOIN licenses lic ON l.license_id = lic.id ORDER BY l.download_time DESC LIMIT 10; ``` **示例输出:** ``` device_sn | download_time | ip_address | model | expiry GD30-20260430-001 | 2026-04-30 16:30:00 | 192.168.1.100 | GD-30 | 2027-04-30 GD30-20260430-002 | 2026-04-30 16:25:00 | 192.168.1.101 | GD-30 | 2027-04-30 ``` ## 6. 错误场景演示 ### 场景A: 设备不存在 ```bash curl "http://localhost:3000/api/licenses/download?sn=INVALID-SN" ``` **响应:** ```json { "error": "设备不存在" } ``` **HTTP状态码:** 404 ### 场景B: 无有效授权 ```bash curl "http://localhost:3000/api/licenses/download?sn=GD30-NO-LICENSE" ``` **响应:** ```json { "error": "该设备暂无有效授权", "deviceSN": "GD30-NO-LICENSE", "deviceModel": "GD-30 Supreme" } ``` **HTTP状态码:** 404 ### 场景C: 缺少SN参数 ```bash curl "http://localhost:3000/api/licenses/download" ``` **响应:** ```json { "error": "设备SN不能为空" } ``` **HTTP状态码:** 400 ## 7. 性能测试演示 ### 测试工具: Apache Bench (ab) ```bash # 模拟100个并发请求,总共1000次请求 ab -n 1000 -c 100 "http://localhost:3000/api/licenses/download?sn=GD30-TEST-001" ``` **预期结果:** ``` Requests per second: 500.00 [#/sec] (mean) Time per request: 200.000 [ms] (mean) Time per request: 2.000 [ms] (mean, across all concurrent requests) ``` ### 优化建议 1. 首次生成后缓存到数据库,避免重复计算 2. 为licenses表添加索引: ```sql CREATE INDEX idx_license_device_sn ON licenses(device_sn); CREATE INDEX idx_license_model ON licenses(model, status, expiry); ``` 3. 生产环境使用Redis缓存热点授权 ## 8. 安全测试演示 ### 测试签名验证 ```javascript // 正常授权文件 const validLicense = await fetchLicense('GD30-TEST-001'); console.log(verifySignature(validLicense)); // true // 篡改后的授权文件 const tamperedLicense = {...validLicense, validUntil: '2099-12-31'}; console.log(verifySignature(tamperedLicense)); // false ``` ### 测试SQL注入防护 ```bash # 尝试SQL注入 curl "http://localhost:3000/api/licenses/download?sn='; DROP TABLE devices; --" ``` **结果:** - 使用参数化查询,SQL注入无效 - 返回"设备不存在"错误 ## 9. 移动端适配说明 ### iOS App (Swift) ```swift func fetchLicense(deviceSN: String, completion: @escaping (Result) -> Void) { let url = URL(string: "http://your-server.com/api/licenses/download?sn=\(deviceSN)")! URLSession.shared.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(error)) return } guard let data = data, let license = try? JSONDecoder().decode(License.self, from: data) else { completion(.failure(NSError(domain: "Invalid response", code: -1))) return } completion(.success(license)) }.resume() } ``` ### Android App (Kotlin) ```kotlin suspend fun fetchLicense(deviceSN: String): License { val response = httpClient.get("http://your-server.com/api/licenses/download?sn=$deviceSN") if (!response.isSuccess) { throw IOException("Failed to fetch license") } return response.body() } ``` ## 10. 监控和告警 ### 关键指标监控 1. **API响应时间** - P95 < 500ms - P99 < 1000ms 2. **错误率** - 4xx错误 < 5% - 5xx错误 < 1% 3. **下载次数统计** - 每日下载总量 - 按设备型号分组统计 - 异常下载频率检测 ### 告警规则 ```yaml alerts: - name: high_error_rate condition: error_rate > 5% duration: 5m action: send_notification - name: slow_response condition: p95_latency > 1000ms duration: 10m action: send_notification - name: unusual_download_pattern condition: downloads_per_minute > 100 duration: 2m action: send_notification_and_block_ip ``` --- **提示**: 实际使用时可以配合截图工具(如Snipaste、Greenshot)截取各个界面的实际效果,添加到文档中以便更直观地展示功能。