改進授權流程為自動綁定模式
Browse files🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- LICENSE_WORKFLOW.md +105 -93
- README.md +14 -15
- app/services/license_service.py +8 -4
- frontend/js/components.js +4 -25
LICENSE_WORKFLOW.md
CHANGED
|
@@ -6,60 +6,9 @@ KSTools License Manager 是一個為 Revit Plugin 設計的授權管理系統,
|
|
| 6 |
|
| 7 |
## 授權流程詳細說明
|
| 8 |
|
| 9 |
-
### 1.
|
| 10 |
|
| 11 |
-
#### 1.1
|
| 12 |
-
```csharp
|
| 13 |
-
// HardwareManager.cs 中的實作
|
| 14 |
-
public class HardwareManager
|
| 15 |
-
{
|
| 16 |
-
public static string GetHardwareId()
|
| 17 |
-
{
|
| 18 |
-
var hwInfo = "";
|
| 19 |
-
|
| 20 |
-
// 取得 CPU ProcessorId
|
| 21 |
-
using (var searcher = new ManagementObjectSearcher("SELECT ProcessorId FROM Win32_Processor"))
|
| 22 |
-
{
|
| 23 |
-
foreach (var obj in searcher.Get())
|
| 24 |
-
{
|
| 25 |
-
hwInfo += obj["ProcessorId"]?.ToString();
|
| 26 |
-
break;
|
| 27 |
-
}
|
| 28 |
-
}
|
| 29 |
-
|
| 30 |
-
// 取得主機板序號
|
| 31 |
-
using (var searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard"))
|
| 32 |
-
{
|
| 33 |
-
foreach (var obj in searcher.Get())
|
| 34 |
-
{
|
| 35 |
-
hwInfo += obj["SerialNumber"]?.ToString();
|
| 36 |
-
break;
|
| 37 |
-
}
|
| 38 |
-
}
|
| 39 |
-
|
| 40 |
-
// 生成 SHA256 Hash 並取前32位
|
| 41 |
-
using (var sha256 = SHA256.Create())
|
| 42 |
-
{
|
| 43 |
-
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(hwInfo));
|
| 44 |
-
return Convert.ToBase64String(hash).Substring(0, 32);
|
| 45 |
-
}
|
| 46 |
-
}
|
| 47 |
-
}
|
| 48 |
-
```
|
| 49 |
-
|
| 50 |
-
#### 1.2 用戶操作步驟
|
| 51 |
-
1. 開啟 Revit Plugin
|
| 52 |
-
2. 點擊「取得授權」或「授權管理」按鈕
|
| 53 |
-
3. 系統自動生成 32 位硬體指紋
|
| 54 |
-
4. 用戶複製硬體指紋
|
| 55 |
-
5. 聯繫管理員提供:
|
| 56 |
-
- 用戶名稱
|
| 57 |
-
- 硬體指紋 (32位字符)
|
| 58 |
-
- 所需授權期間
|
| 59 |
-
|
| 60 |
-
### 2. 管理員操作 (後台管理)
|
| 61 |
-
|
| 62 |
-
#### 2.1 建立新授權
|
| 63 |
1. 登入管理後台
|
| 64 |
2. 進入「用戶管理」頁面
|
| 65 |
3. 點擊「建立新授權」按鈕
|
|
@@ -67,7 +16,6 @@ public class HardwareManager
|
|
| 67 |
|
| 68 |
**必要欄位:**
|
| 69 |
- **用戶名稱**: 識別用戶的名稱
|
| 70 |
-
- **硬體指紋**: 用戶提供的32位硬體指紋
|
| 71 |
- **有效天數**: 授權有效期限
|
| 72 |
- 7天 (試用)
|
| 73 |
- 30天
|
|
@@ -79,47 +27,104 @@ public class HardwareManager
|
|
| 79 |
- **電子郵件**: 聯繫用途
|
| 80 |
- **備註**: 內部記錄使用
|
| 81 |
|
| 82 |
-
####
|
| 83 |
- 用戶名稱不可為空
|
| 84 |
-
- 硬體指紋必須為32位字符
|
| 85 |
- 有效天數必須選擇
|
| 86 |
-
- 硬體指紋自動
|
| 87 |
|
| 88 |
-
####
|
| 89 |
系統自動生成:
|
| 90 |
-
- 唯一授權碼 (32位字符
|
| 91 |
- 到期時間計算
|
| 92 |
- 建立時間記錄
|
|
|
|
| 93 |
|
| 94 |
-
###
|
| 95 |
|
| 96 |
-
####
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
2. 系統驗證授權碼有效性
|
| 99 |
-
3. 檢查硬體指紋是否匹配
|
| 100 |
-
4.
|
| 101 |
-
5. 授權
|
| 102 |
|
| 103 |
-
#### 3.
|
| 104 |
1. Plugin 啟動時自動驗證
|
| 105 |
2. 檢查授權是否過期
|
| 106 |
3. 驗證硬體指紋匹配
|
| 107 |
-
4.
|
| 108 |
-
5. 更新
|
| 109 |
|
| 110 |
### 4. 授權狀態管理
|
| 111 |
|
| 112 |
#### 4.1 授權狀態分類
|
| 113 |
-
- **未啟用**: 已建立但未使用的授權
|
| 114 |
-
- **啟用中**: 正常使用中的授權
|
| 115 |
- **已過期**: 超過有效期限的授權
|
| 116 |
- **已停用**: 管理員手動停用的授權
|
| 117 |
|
| 118 |
-
#### 4.2 硬體綁定規則
|
| 119 |
-
-
|
| 120 |
-
-
|
| 121 |
-
-
|
| 122 |
-
- 需
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
### 5. 系統記錄與監控
|
| 125 |
|
|
@@ -139,29 +144,36 @@ public class HardwareManager
|
|
| 139 |
|
| 140 |
### 6. 安全特性
|
| 141 |
|
| 142 |
-
#### 6.1 硬體綁定安全
|
| 143 |
-
-
|
| 144 |
-
- SHA256
|
| 145 |
-
- 32位字符長度
|
| 146 |
-
-
|
| 147 |
|
| 148 |
-
#### 6.2 授權保護
|
| 149 |
-
- 授權碼
|
| 150 |
-
-
|
| 151 |
-
-
|
| 152 |
-
-
|
|
|
|
| 153 |
|
| 154 |
## 故障排除
|
| 155 |
|
| 156 |
-
### 常見問題
|
| 157 |
-
1. **
|
|
|
|
|
|
|
| 158 |
2. **授權過期**: 超過設定的有效期限
|
| 159 |
-
3. **
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
## 技術規格
|
| 167 |
|
|
|
|
| 6 |
|
| 7 |
## 授權流程詳細說明
|
| 8 |
|
| 9 |
+
### 1. 管理員操作 (後台管理)
|
| 10 |
|
| 11 |
+
#### 1.1 建立新授權 (簡化流程)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
1. 登入管理後台
|
| 13 |
2. 進入「用戶管理」頁面
|
| 14 |
3. 點擊「建立新授權」按鈕
|
|
|
|
| 16 |
|
| 17 |
**必要欄位:**
|
| 18 |
- **用戶名稱**: 識別用戶的名稱
|
|
|
|
| 19 |
- **有效天數**: 授權有效期限
|
| 20 |
- 7天 (試用)
|
| 21 |
- 30天
|
|
|
|
| 27 |
- **電子郵件**: 聯繫用途
|
| 28 |
- **備註**: 內部記錄使用
|
| 29 |
|
| 30 |
+
#### 1.2 系統驗證
|
| 31 |
- 用戶名稱不可為空
|
|
|
|
| 32 |
- 有效天數必須選擇
|
| 33 |
+
- **無需硬體指紋**: 系統將在首次啟用時自動綁定
|
| 34 |
|
| 35 |
+
#### 1.3 授權生成
|
| 36 |
系統自動生成:
|
| 37 |
+
- 唯一授權碼 (32位字符)
|
| 38 |
- 到期時間計算
|
| 39 |
- 建立時間記錄
|
| 40 |
+
- **硬體指紋設為 null** (等待首次綁定)
|
| 41 |
|
| 42 |
+
### 2. 用戶端操作 (Revit Plugin)
|
| 43 |
|
| 44 |
+
#### 2.1 硬體指紋生成 (自動)
|
| 45 |
+
```csharp
|
| 46 |
+
// HardwareFingerprint.cs 中的實作
|
| 47 |
+
public class HardwareFingerprint
|
| 48 |
+
{
|
| 49 |
+
public static string GetHardwareId()
|
| 50 |
+
{
|
| 51 |
+
var hwInfo = "";
|
| 52 |
+
|
| 53 |
+
// 取得 CPU ProcessorId
|
| 54 |
+
string cpuId = GetCpuId();
|
| 55 |
+
if (!string.IsNullOrEmpty(cpuId))
|
| 56 |
+
hwInfo += cpuId;
|
| 57 |
+
|
| 58 |
+
// 取得主機板序號
|
| 59 |
+
string motherboardSerial = GetMotherboardSerial();
|
| 60 |
+
if (!string.IsNullOrEmpty(motherboardSerial))
|
| 61 |
+
hwInfo += motherboardSerial;
|
| 62 |
+
|
| 63 |
+
// 備選方案:MAC 地址
|
| 64 |
+
if (string.IsNullOrEmpty(hwInfo))
|
| 65 |
+
hwInfo = GetMacAddress();
|
| 66 |
+
|
| 67 |
+
// 生成 SHA256 Hash 並取前32位
|
| 68 |
+
using (var sha256 = SHA256.Create())
|
| 69 |
+
{
|
| 70 |
+
var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(hwInfo + "KSTOOLS_SALT"));
|
| 71 |
+
string hashString = Convert.ToBase64String(hash);
|
| 72 |
+
hashString = hashString.Replace("+", "").Replace("/", "").Replace("=", "");
|
| 73 |
+
return hashString.Substring(0, 32);
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
}
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
#### 2.2 用戶操作步驟 (簡化)
|
| 80 |
+
1. 開啟 Revit Plugin
|
| 81 |
+
2. 點擊「授權管理」按鈕
|
| 82 |
+
3. 輸入管理員提供的授權碼
|
| 83 |
+
4. **系統自動生成並綁定硬體指紋**
|
| 84 |
+
5. 立即啟用成功,無需額外操作
|
| 85 |
+
|
| 86 |
+
### 3. 授權驗證流程 (自動綁定)
|
| 87 |
+
|
| 88 |
+
#### 3.1 首次啟用 (自動綁定)
|
| 89 |
+
1. 用戶在 Revit Plugin 輸入授權碼
|
| 90 |
+
2. 系統驗證授權碼有效性
|
| 91 |
+
3. **檢查是否為首次啟用** (`activated_at` 為 null)
|
| 92 |
+
4. **自動生成硬體指紋並綁定**
|
| 93 |
+
5. 記錄啟用時間和硬體資訊
|
| 94 |
+
6. 授權狀態變更為「已啟用」
|
| 95 |
+
|
| 96 |
+
#### 3.2 重複啟用 (驗證綁定)
|
| 97 |
+
1. 用戶再次輸入授權碼
|
| 98 |
2. 系統驗證授權碼有效性
|
| 99 |
+
3. **檢查硬體指紋是否匹配**
|
| 100 |
+
4. 匹配成功 → 啟用成功
|
| 101 |
+
5. 不匹配 → 顯示「此授權已綁定其他設備」
|
| 102 |
|
| 103 |
+
#### 3.3 日常驗證 (快取支援)
|
| 104 |
1. Plugin 啟動時自動驗證
|
| 105 |
2. 檢查授權是否過期
|
| 106 |
3. 驗證硬體指紋匹配
|
| 107 |
+
4. **支援 24 小時離線使用** (快取機制)
|
| 108 |
+
5. 記錄使用時間並更新最後使用時間
|
| 109 |
|
| 110 |
### 4. 授權狀態管理
|
| 111 |
|
| 112 |
#### 4.1 授權狀態分類
|
| 113 |
+
- **未啟用**: 已建立但未首次使用的授權 (`activated_at` 為 null)
|
| 114 |
+
- **啟用中**: 已綁定硬體且正常使用中的授權
|
| 115 |
- **已過期**: 超過有效期限的授權
|
| 116 |
- **已停用**: 管理員手動停用的授權
|
| 117 |
|
| 118 |
+
#### 4.2 硬體綁定規則 (自動綁定模式)
|
| 119 |
+
- **首次啟用自動綁定**: 輸入授權碼後自動綁定當前硬體
|
| 120 |
+
- **一機一碼**: 每個授權只能在一台設備上使用
|
| 121 |
+
- **硬體指紋基於**: CPU ProcessorId + 主機板序號 + MAC 地址 (備選)
|
| 122 |
+
- **硬體變更影響**: 更換 CPU 或主機板將導致指紋變更,需重新授權
|
| 123 |
+
|
| 124 |
+
#### 4.3 安全機制
|
| 125 |
+
- **防止授權碼濫用**: 首次綁定後無法在其他設備使用
|
| 126 |
+
- **離線支援**: 24 小時本地快取,網路中斷仍可使用
|
| 127 |
+
- **自動過期**: 系統自動檢查並處理過期授權
|
| 128 |
|
| 129 |
### 5. 系統記錄與監控
|
| 130 |
|
|
|
|
| 144 |
|
| 145 |
### 6. 安全特性
|
| 146 |
|
| 147 |
+
#### 6.1 硬體綁定安全 (增強版)
|
| 148 |
+
- **多重硬體識別**: CPU ProcessorId + 主機板序號 + MAC 地址備選
|
| 149 |
+
- **SHA256 + Base64 編碼**: 強化加密算法
|
| 150 |
+
- **32位字符長度**: 標準長度確保唯一性
|
| 151 |
+
- **KSTOOLS_SALT**: 專用鹽值增加安全性
|
| 152 |
|
| 153 |
+
#### 6.2 授權保護 (自動綁定模式)
|
| 154 |
+
- **首次綁定保護**: 防止授權碼被搶先綁定到錯誤設備
|
| 155 |
+
- **本地加密快取**: Windows Registry 加密儲存
|
| 156 |
+
- **時間戳記驗證**: 防止時間回撥攻擊
|
| 157 |
+
- **IP 地址記錄**: 完整的使用追蹤
|
| 158 |
+
- **24小時離線支援**: 網路中斷時的可用性保障
|
| 159 |
|
| 160 |
## 故障排除
|
| 161 |
|
| 162 |
+
### 常見問題 (更新版)
|
| 163 |
+
1. **「此授權已綁定其他設備」**:
|
| 164 |
+
- 原因: 授權已在其他設備上首次啟用
|
| 165 |
+
- 或者: 更換了 CPU 或主機板導致硬體指紋變更
|
| 166 |
2. **授權過期**: 超過設定的有效期限
|
| 167 |
+
3. **網路連接錯誤**: API 服務無法連接
|
| 168 |
+
4. **首次啟用失敗**: 授權碼錯誤或已過期
|
| 169 |
+
|
| 170 |
+
### 解決方案 (更新版)
|
| 171 |
+
1. **硬體綁定問題**:
|
| 172 |
+
- 確認是否在正確的設備上啟用
|
| 173 |
+
- 如需變更設備,請聯繫管理員重新建立授權
|
| 174 |
+
2. **過期問題**: 管理員可延長授權期限
|
| 175 |
+
3. **網路問題**: 檢查網路連接,或等待離線快取生效
|
| 176 |
+
4. **啟用失敗**: 確認授權碼正確性,檢查是否已過期
|
| 177 |
|
| 178 |
## 技術規格
|
| 179 |
|
README.md
CHANGED
|
@@ -24,25 +24,24 @@ pinned: false
|
|
| 24 |
|
| 25 |
### 🎯 核心授權流程
|
| 26 |
|
| 27 |
-
#### 用戶端操作 (Revit Plugin)
|
| 28 |
-
1. **硬體指紋生成** - 系統自動生成 32 位硬體指紋 (CPU + 主機板)
|
| 29 |
-
2. **取得指紋** - 用戶點擊按鈕複製硬體指紋
|
| 30 |
-
3. **聯繫管理員** - 提供用戶名稱和硬體指紋
|
| 31 |
-
|
| 32 |
#### 管理員操作 (Web 後台)
|
| 33 |
1. **建立授權** - 填入必要資訊:
|
| 34 |
- 用戶名稱 *
|
| 35 |
-
- 硬體指紋 * (32位字符)
|
| 36 |
- 有效天數 * (7天/30天/90天/1年/永久)
|
| 37 |
- 電子郵件 (選填)
|
| 38 |
- 備註 (選填)
|
| 39 |
-
2. **生成授權碼** - 系統自動產生 32位字符授權碼
|
| 40 |
3. **提供給用戶** - 將授權碼交付給用戶
|
| 41 |
|
| 42 |
-
####
|
| 43 |
-
1. **授權
|
| 44 |
-
2. **
|
| 45 |
-
3. **
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
|
| 47 |
### 🎨 現代化前端
|
| 48 |
- **零框架依賴**: 純 HTML/CSS/JS,載入迅速
|
|
@@ -52,10 +51,10 @@ pinned: false
|
|
| 52 |
- **即時更新**: 無需重新載入的 SPA 體驗
|
| 53 |
|
| 54 |
### 🛡️ 安全機制
|
| 55 |
-
- 硬體綁定授權
|
| 56 |
-
- JWT Token 認證
|
| 57 |
-
- 加密通訊協議
|
| 58 |
-
-
|
| 59 |
|
| 60 |
### 📊 管理功能
|
| 61 |
- 用戶授權管理
|
|
|
|
| 24 |
|
| 25 |
### 🎯 核心授權流程
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
#### 管理員操作 (Web 後台)
|
| 28 |
1. **建立授權** - 填入必要資訊:
|
| 29 |
- 用戶名稱 *
|
|
|
|
| 30 |
- 有效天數 * (7天/30天/90天/1年/永久)
|
| 31 |
- 電子郵件 (選填)
|
| 32 |
- 備註 (選填)
|
| 33 |
+
2. **生成授權碼** - 系統自動產生 32位字符授權碼
|
| 34 |
3. **提供給用戶** - 將授權碼交付給用戶
|
| 35 |
|
| 36 |
+
#### 用戶端操作 (Revit Plugin)
|
| 37 |
+
1. **輸入授權碼** - 用戶在 Plugin 中輸入管理員提供的授權碼
|
| 38 |
+
2. **自動綁定** - 首次啟用時系統自動生成並綁定 32位硬體指紋 (CPU + 主機板)
|
| 39 |
+
3. **即時啟用** - 無需額外操作,立即啟用成功
|
| 40 |
+
|
| 41 |
+
#### 持續驗證
|
| 42 |
+
1. **自動驗證** - Plugin 每次使用時自動驗證授權有效性
|
| 43 |
+
2. **硬體綁定** - 確保授權只能在綁定的設備上使用
|
| 44 |
+
3. **離線支援** - 支援 24 小時離線使用 (快取機制)
|
| 45 |
|
| 46 |
### 🎨 現代化前端
|
| 47 |
- **零框架依賴**: 純 HTML/CSS/JS,載入迅速
|
|
|
|
| 51 |
- **即時更新**: 無需重新載入的 SPA 體驗
|
| 52 |
|
| 53 |
### 🛡️ 安全機制
|
| 54 |
+
- **硬體綁定**: 首次啟用自動綁定,防止授權碼被濫用
|
| 55 |
+
- **JWT Token 認證**: 管理後台安全認證
|
| 56 |
+
- **加密通訊**: HTTPS 加密通訊協議
|
| 57 |
+
- **一機一碼**: 每個授權碼只能在一台設備上使用
|
| 58 |
|
| 59 |
### 📊 管理功能
|
| 60 |
- 用戶授權管理
|
app/services/license_service.py
CHANGED
|
@@ -52,10 +52,10 @@ class LicenseService:
|
|
| 52 |
"license_code": license_code,
|
| 53 |
"user_name": license_data.user_name,
|
| 54 |
"user_email": license_data.user_email,
|
| 55 |
-
"hardware_id":
|
| 56 |
"expires_at": expires_at.isoformat(),
|
| 57 |
"is_active": True,
|
| 58 |
-
"activated_at":
|
| 59 |
}
|
| 60 |
|
| 61 |
print(f"🔄 Creating license with data: {license_record}")
|
|
@@ -119,8 +119,12 @@ class LicenseService:
|
|
| 119 |
message="授權已過期"
|
| 120 |
)
|
| 121 |
|
| 122 |
-
# 檢查硬體綁定
|
| 123 |
-
if license_data["
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
await self._log_usage(license_id, "activate", client_ip, error_message="硬體ID不符")
|
| 125 |
return ActivationResponse(
|
| 126 |
success=False,
|
|
|
|
| 52 |
"license_code": license_code,
|
| 53 |
"user_name": license_data.user_name,
|
| 54 |
"user_email": license_data.user_email,
|
| 55 |
+
"hardware_id": None, # 方案B:創建時不綁定硬體,首次啟用時自動綁定
|
| 56 |
"expires_at": expires_at.isoformat(),
|
| 57 |
"is_active": True,
|
| 58 |
+
"activated_at": None # 首次啟用時才設定
|
| 59 |
}
|
| 60 |
|
| 61 |
print(f"🔄 Creating license with data: {license_record}")
|
|
|
|
| 119 |
message="授權已過期"
|
| 120 |
)
|
| 121 |
|
| 122 |
+
# 檢查硬體綁定狀態 (方案B:首次啟用自動綁定)
|
| 123 |
+
if license_data["activated_at"] is None:
|
| 124 |
+
# 首次啟用:允許綁定到當前硬體
|
| 125 |
+
print(f"🔄 首次啟用授權,綁定硬體ID: {activation.hardware_id}")
|
| 126 |
+
elif license_data["hardware_id"] != activation.hardware_id:
|
| 127 |
+
# 已啟用過,但硬體ID不匹配
|
| 128 |
await self._log_usage(license_id, "activate", client_ip, error_message="硬體ID不符")
|
| 129 |
return ActivationResponse(
|
| 130 |
success=False,
|
frontend/js/components.js
CHANGED
|
@@ -73,7 +73,7 @@ class Components {
|
|
| 73 |
</label>
|
| 74 |
<input type="text" id="userName" name="userName" class="form-input" required
|
| 75 |
placeholder="輸入使用者名稱">
|
| 76 |
-
<small class="form-help">此名稱將
|
| 77 |
</div>
|
| 78 |
|
| 79 |
<div class="form-group">
|
|
@@ -86,15 +86,6 @@ class Components {
|
|
| 86 |
<small class="form-help">選填:用於聯繫和通知</small>
|
| 87 |
</div>
|
| 88 |
|
| 89 |
-
<div class="form-group">
|
| 90 |
-
<label for="hardwareId" class="form-label">
|
| 91 |
-
<i class="fas fa-desktop"></i>
|
| 92 |
-
硬體ID *
|
| 93 |
-
</label>
|
| 94 |
-
<input type="text" id="hardwareId" name="hardwareId" class="form-input" required
|
| 95 |
-
placeholder="從 Revit Plugin 取得的 32 位硬體ID" maxlength="32">
|
| 96 |
-
<small class="form-help">用戶從 Revit Plugin 取得的硬體ID (32 位字符)</small>
|
| 97 |
-
</div>
|
| 98 |
|
| 99 |
<div class="form-group">
|
| 100 |
<label for="validDays" class="form-label">
|
|
@@ -126,9 +117,9 @@ class Components {
|
|
| 126 |
硬體綁定機制說明
|
| 127 |
</div>
|
| 128 |
<div class="info-content">
|
| 129 |
-
<p>•
|
| 130 |
-
<p>•
|
| 131 |
-
<p>•
|
| 132 |
</div>
|
| 133 |
</div>
|
| 134 |
|
|
@@ -166,7 +157,6 @@ class Components {
|
|
| 166 |
|
| 167 |
// 驗證必要欄位
|
| 168 |
const userName = formData.get('userName')?.trim();
|
| 169 |
-
const hardwareId = formData.get('hardwareId')?.trim();
|
| 170 |
const validDays = formData.get('validDays');
|
| 171 |
|
| 172 |
if (!userName) {
|
|
@@ -174,16 +164,6 @@ class Components {
|
|
| 174 |
return;
|
| 175 |
}
|
| 176 |
|
| 177 |
-
if (!hardwareId) {
|
| 178 |
-
Utils.showError('驗證失敗', '請輸入硬體ID');
|
| 179 |
-
return;
|
| 180 |
-
}
|
| 181 |
-
|
| 182 |
-
if (hardwareId.length !== 32) {
|
| 183 |
-
Utils.showError('驗證失敗', '硬體ID必須為 32 位字符');
|
| 184 |
-
return;
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
if (!validDays) {
|
| 188 |
Utils.showError('驗證失敗', '請選擇有效天數');
|
| 189 |
return;
|
|
@@ -193,7 +173,6 @@ class Components {
|
|
| 193 |
user_name: userName,
|
| 194 |
user_email: formData.get('email')?.trim() || null,
|
| 195 |
expires_days: parseInt(validDays),
|
| 196 |
-
hardware_id: hardwareId.toUpperCase(), // 統一轉為大寫
|
| 197 |
notes: formData.get('notes')?.trim() || null
|
| 198 |
};
|
| 199 |
|
|
|
|
| 73 |
</label>
|
| 74 |
<input type="text" id="userName" name="userName" class="form-input" required
|
| 75 |
placeholder="輸入使用者名稱">
|
| 76 |
+
<small class="form-help">此名稱將顯示在授權記錄中</small>
|
| 77 |
</div>
|
| 78 |
|
| 79 |
<div class="form-group">
|
|
|
|
| 86 |
<small class="form-help">選填:用於聯繫和通知</small>
|
| 87 |
</div>
|
| 88 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
<div class="form-group">
|
| 91 |
<label for="validDays" class="form-label">
|
|
|
|
| 117 |
硬體綁定機制說明
|
| 118 |
</div>
|
| 119 |
<div class="info-content">
|
| 120 |
+
<p>• 使用者首次輸入授權碼時會自動綁定硬體</p>
|
| 121 |
+
<p>• 系統會自動生成32位硬體指紋 (CPU ProcessorId + 主機板序號)</p>
|
| 122 |
+
<p>• 每個授權碼只能在一台設備上啟用使用</p>
|
| 123 |
</div>
|
| 124 |
</div>
|
| 125 |
|
|
|
|
| 157 |
|
| 158 |
// 驗證必要欄位
|
| 159 |
const userName = formData.get('userName')?.trim();
|
|
|
|
| 160 |
const validDays = formData.get('validDays');
|
| 161 |
|
| 162 |
if (!userName) {
|
|
|
|
| 164 |
return;
|
| 165 |
}
|
| 166 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
if (!validDays) {
|
| 168 |
Utils.showError('驗證失敗', '請選擇有效天數');
|
| 169 |
return;
|
|
|
|
| 173 |
user_name: userName,
|
| 174 |
user_email: formData.get('email')?.trim() || null,
|
| 175 |
expires_days: parseInt(validDays),
|
|
|
|
| 176 |
notes: formData.get('notes')?.trim() || null
|
| 177 |
};
|
| 178 |
|