secure-electron-license-keys 是一個專門為 Electron 應用設計的 npm 包,用于實現離線許可證密鑰的創建、驗證和管理,幫助開發者保護應用程序,確保只有擁有合法許可證的用戶才能使用。以下是關于它的詳細介紹:
在 Electron 應用中集成 secure-electron-license-keys
包主要涉及密鑰對生成、許可證創建(服務端)和客戶端驗證三個核心步驟。以下是詳細的集成流程:
步驟 1:準備工作
-
安裝依賴
在 Electron 項目中安裝包:npm install secure-electron-license-keys --save
-
項目結構建議
建議按以下結構組織文件(區分服務端和客戶端代碼):your-electron-app/ ├── server/ # 服務端(生成密鑰對和許可證) │ ├── private.pem # 私鑰(保密,不隨客戶端打包) │ └── generate-license.js # 生成許可證的腳本 ├── src/ │ ├── public.pem # 公鑰(客戶端使用,隨應用打包) │ ├── main.js # Electron 主進程 │ └── renderer/ # 渲染進程(許可證輸入界面)
步驟 2:生成 RSA 密鑰對(服務端/開發者操作)
密鑰對用于加密和解密許可證,私鑰僅保存在服務端,公鑰內置到客戶端。
創建 server/generate-keys.js
腳本:
const { generateKeyPair } = require("secure-electron-license-keys");
const path = require("path");// 生成密鑰對并保存到文件
generateKeyPair({privateKeyPath: path.join(__dirname, "private.pem"), // 私鑰路徑(絕對路徑)publicKeyPath: path.join(__dirname, "../src/public.pem"), // 公鑰路徑(客戶端使用)keySize: 2048 // 密鑰長度(推薦 2048 或 4096)
}).then(() => {console.log("密鑰對生成成功!");
}).catch(err => {console.error("生成失敗:", err);
});
運行腳本生成密鑰:
node server/generate-keys.js
生成后,將 public.pem
移動到客戶端代碼目錄(如 src/
),private.pem
留在服務端并嚴格保密。
步驟 3:創建許可證(服務端/開發者操作)
當用戶購買后,服務端使用私鑰生成許可證,包含用戶信息、有效期等數據。
創建 server/generate-license.js
腳本:
const { createLicense } = require("secure-electron-license-keys");
const path = require("path");
const fs = require("fs");// 自定義許可證數據
const licenseData = {userId: "user123", // 用戶唯一標識email: "user@example.com", // 用戶郵箱expires: "2025-12-31", // 過期時間(格式:YYYY-MM-DD)appVersion: "1.0.0", // 允許的應用版本features: ["export", "cloudSync"] // 允許的功能
};// 生成許可證
createLicense({privateKeyPath: path.join(__dirname, "private.pem"), // 私鑰路徑data: licenseData
}).then(licenseKey => {// 保存許可證(可發送給用戶或存儲到數據庫)fs.writeFileSync(path.join(__dirname, `license-${licenseData.userId}.key`),licenseKey);console.log("許可證生成成功:", licenseKey);
}).catch(err => {console.error("生成失敗:", err);
});
運行腳本生成許可證:
node server/generate-license.js
生成的許可證密鑰(如 license-user123.key
)可通過郵件等方式發送給用戶。
步驟 4:客戶端集成(Electron 應用中)
客戶端需要實現:許可證輸入界面、驗證邏輯、本地保存和啟動時自動驗證。
4.1 主進程配置(main.js)
在主進程中初始化許可證管理器,并提供驗證接口給渲染進程:
const { app, BrowserWindow, ipcMain } = require("electron");
const { LicenseManager } = require("secure-electron-license-keys");
const path = require("path");// 初始化許可證管理器
const licenseManager = new LicenseManager({publicKeyPath: path.join(__dirname, "public.pem"), // 公鑰路徑licensePath: path.join(app.getPath("userData"), "license.key") // 本地保存路徑
});// 驗證許可證(供渲染進程調用)
ipcMain.handle("verify-license", async (event, licenseKey) => {try {const result = await licenseManager.verifyLicense(licenseKey);if (result.valid) {// 驗證成功,保存許可證到本地await licenseManager.saveLicense(licenseKey);}return result;} catch (err) {return { valid: false, error: err.message };}
});// 啟動時自動驗證本地許可證
ipcMain.handle("check-saved-license", async () => {try {const savedLicense = await licenseManager.loadLicense();if (!savedLicense) return { valid: false, error: "未找到許可證" };const result = await licenseManager.verifyLicense(savedLicense);return result;} catch (err) {return { valid: false, error: err.message };}
});// 創建窗口等常規邏輯...
function createWindow() {const mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences: {preload: path.join(__dirname, "preload.js"), // 預加載腳本contextIsolation: true}});mainWindow.loadFile("src/renderer/index.html");
}app.whenReady().then(createWindow);
4.2 預加載腳本(preload.js)
暴露 IPC 接口給渲染進程:
const { contextBridge, ipcRenderer } = require("electron");contextBridge.exposeInMainWorld("licenseAPI", {verifyLicense: (key) => ipcRenderer.invoke("verify-license", key),checkSavedLicense: () => ipcRenderer.invoke("check-saved-license")
});
4.3 渲染進程界面(許可證輸入與驗證)
創建一個簡單的 HTML 界面(src/renderer/index.html
),讓用戶輸入許可證密鑰:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>許可證驗證</title><style>.container { margin: 20px; }input { width: 300px; padding: 8px; margin: 10px 0; }button { padding: 8px 16px; cursor: pointer; }.status { margin-top: 10px; padding: 8px; }.valid { background: #d4edda; color: #155724; }.invalid { background: #f8d7da; color: #721c24; }</style>
</head>
<body><div class="container"><h2>請輸入許可證密鑰</h2><input type="text" id="licenseKey" placeholder="粘貼許可證密鑰"><button onclick="verify()">驗證</button><div id="status" class="status"></div></div><script>// 頁面加載時檢查本地是否有已保存的許可證window.addEventListener("DOMContentLoaded", async () => {const result = await window.licenseAPI.checkSavedLicense();updateStatus(result);});// 驗證用戶輸入的許可證async function verify() {const key = document.getElementById("licenseKey").value;if (!key) {alert("請輸入許可證密鑰");return;}const result = await window.licenseAPI.verifyLicense(key);updateStatus(result);}// 更新狀態顯示function updateStatus(result) {const statusEl = document.getElementById("status");if (result.valid) {statusEl.textContent = `許可證有效!用戶:${result.data.email},過期時間:${result.data.expires}`;statusEl.className = "status valid";// 驗證成功后可跳轉到主應用界面} else {statusEl.textContent = `驗證失敗:${result.error}`;statusEl.className = "status invalid";}}</script>
</body>
</html>
步驟 5:功能限制邏輯
根據許可證驗證結果限制應用功能(例如在主界面中):
// 主應用界面的腳本中
async function initApp() {const licenseResult = await window.licenseAPI.checkSavedLicense();if (!licenseResult.valid) {// 未通過驗證,跳轉到許可證輸入頁window.location.href = "license.html";return;}// 根據許可證數據啟用/禁用功能const features = licenseResult.data.features;if (!features.includes("export")) {document.getElementById("exportBtn").disabled = true;document.getElementById("exportBtn").title = "需要高級許可證";}
}
關鍵注意事項
- 私鑰安全:
private.pem
絕不能隨客戶端打包,僅限服務端使用,泄露會導致許可證可被偽造。 - 公鑰保護:公鑰會內置到客戶端,可通過代碼混淆工具(如
electron-obfuscator
)防止被輕易提取。 - 離線局限性:該包僅支持離線驗證,若需遠程吊銷許可證,需額外添加聯網檢查(如定期向服務器驗證許可證狀態)。
- 版本兼容:確保
secure-electron-license-keys
版本與 Electron 版本兼容(建議使用最新穩定版)。
通過以上步驟,你的 Electron 應用將具備基本的許可證驗證功能,可有效控制用戶訪問權限。