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 应用将具备基本的许可证验证功能,可有效控制用户访问权限。