enterprise-saa-s-dashboard-.../DEMO_GUIDE.md

13 KiB
Raw Permalink Blame History

授权文件功能演示说明

📸 功能界面说明

由于这是文本环境,以下用文字描述各功能的界面和操作流程。

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发起请求

GET /api/licenses/download?sn=GD30-20260430-001

Step 2: 平台处理流程

接收请求
  ↓
验证设备SN是否存在
  ↓
查找设备级授权 (device_sn匹配)
  ↓ 未找到
查找型号级授权 (model匹配 + 状态生效 + 未过期)
  ↓
获取关联的配置文件
  ↓
生成/读取授权文件JSON
  ↓
记录下载日志 (时间、IP、APP版本)
  ↓
返回JSON响应

Step 3: APP接收响应

{
  "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处理授权

// 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. 数据库查询演示

查看授权记录

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 | 生效   | 已生成

查看下载日志

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: 设备不存在

curl "http://localhost:3000/api/licenses/download?sn=INVALID-SN"

响应:

{
  "error": "设备不存在"
}

HTTP状态码: 404

场景B: 无有效授权

curl "http://localhost:3000/api/licenses/download?sn=GD30-NO-LICENSE"

响应:

{
  "error": "该设备暂无有效授权",
  "deviceSN": "GD30-NO-LICENSE",
  "deviceModel": "GD-30 Supreme"
}

HTTP状态码: 404

场景C: 缺少SN参数

curl "http://localhost:3000/api/licenses/download"

响应:

{
  "error": "设备SN不能为空"
}

HTTP状态码: 400

7. 性能测试演示

测试工具: Apache Bench (ab)

# 模拟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表添加索引
    CREATE INDEX idx_license_device_sn ON licenses(device_sn);
    CREATE INDEX idx_license_model ON licenses(model, status, expiry);
    
  3. 生产环境使用Redis缓存热点授权

8. 安全测试演示

测试签名验证

// 正常授权文件
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注入防护

# 尝试SQL注入
curl "http://localhost:3000/api/licenses/download?sn='; DROP TABLE devices; --"

结果:

  • 使用参数化查询SQL注入无效
  • 返回"设备不存在"错误

9. 移动端适配说明

iOS App (Swift)

func fetchLicense(deviceSN: String, completion: @escaping (Result<License, Error>) -> 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)

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. 下载次数统计

    • 每日下载总量
    • 按设备型号分组统计
    • 异常下载频率检测

告警规则

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截取各个界面的实际效果添加到文档中以便更直观地展示功能。