main.js
const { app, BrowserWindow } = require('electron');
const { getDeviceId } = require('./hardwareId');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true, // 注意:在生产环境中不推荐启用nodeIntegration
contextIsolation: false
}
});
mainWindow.loadFile('index.html');
// 获取设备ID并发送到渲染进程
getDeviceId().then(deviceId => {
console.log('设备唯一ID:', deviceId);
// 当窗口加载完成后发送设备ID
mainWindow.webContents.on('did-finish-load', () => {
mainWindow.webContents.send('device-id', deviceId);
});
}).catch(error => {
console.error('获取设备ID时出错:', error);
});
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
hardwareId.js
const { exec } = require('child_process');
const crypto = require('crypto');
const util = require('util');
// 转换exec为Promise形式,便于异步处理
const execAsync = util.promisify(exec);
/**
* 获取CPU信息
* @returns {Promise<string>} CPU标识符
*/
async function getCpuInfo() {
try {
// 使用wmic命令获取CPU序列号
const { stdout } = await execAsync('wmic cpu get processorid');
// 提取并清理CPU序列号
const cpuId = stdout.split('\n')[1]?.trim() || '';
return cpuId;
} catch (error) {
console.error('获取CPU信息失败:', error);
return '';
}
}
/**
* 获取硬盘信息
* @returns {Promise<string>} 硬盘标识符
*/
async function getDiskInfo() {
try {
// 使用wmic命令获取硬盘序列号(取第一个硬盘)
const { stdout } = await execAsync('wmic diskdrive get serialnumber');
// 提取并清理硬盘序列号
const diskId = stdout.split('\n')[1]?.trim() || '';
return diskId;
} catch (error) {
console.error('获取硬盘信息失败:', error);
return '';
}
}
/**
* 计算设备唯一ID
* @returns {Promise<string>} 设备唯一ID
*/
async function getDeviceId() {
try {
// 获取CPU和硬盘信息
const [cpuId, diskId] = await Promise.all([getCpuInfo(), getDiskInfo()]);
// 如果获取硬件信息失败,使用备选方案
if (!cpuId && !diskId) {
console.warn('无法获取硬件信息,使用系统信息作为备选');
const { stdout } = await execAsync('wmic csproduct get uuid');
const systemId = stdout.split('\n')[1]?.trim() || '';
if (!systemId) {
throw new Error('无法获取任何硬件标识信息');
}
return generateHash(systemId);
}
// 组合硬件信息生成唯一字符串
const hardwareInfo = `${cpuId}|${diskId}`;
// 生成哈希值作为设备ID
return generateHash(hardwareInfo);
} catch (error) {
console.error('计算设备ID失败:', error);
throw error;
}
}
/**
* 生成哈希值
* @param {string} data 要哈希的数据
* @returns {string} 哈希结果
*/
function generateHash(data) {
// 使用SHA-256算法生成哈希
const hash = crypto.createHash('sha256');
hash.update(data);
// 返回十六进制格式的哈希值
return hash.digest('hex');
}
// 导出模块
module.exports = {
getDeviceId,
getCpuInfo,
getDiskInfo
};
使用说明:
-
上述代码通过 Windows 的 WMIC 命令获取硬件信息:
- CPU 信息:使用
wmic cpu get processorid获取 CPU 序列号 - 硬盘信息:使用
wmic diskdrive get serialnumber获取硬盘序列号 - 备选方案:如果上述信息无法获取,使用
wmic csproduct get uuid获取系统 UUID
- CPU 信息:使用
-
计算设备 ID 的过程:
- 组合获取到的硬件信息
- 使用 SHA-256 算法对组合信息进行哈希计算
- 生成的哈希值作为设备唯一 ID
-
在 Electron 中使用:
- 主进程中调用
getDeviceId()方法获取设备 ID - 通过 IPC 通信将设备 ID 发送到渲染进程
- 可以将此 ID 用于注册码生成和验证
- 主进程中调用
注意事项:
- 某些情况下(如虚拟机、某些硬件配置)可能无法获取到完整的硬件信息
- 管理员权限可能会提高硬件信息获取的成功率
- 在生产环境中,建议关闭
nodeIntegration并使用上下文隔离,通过预加载脚本进行安全的 IPC 通信 - 硬件信息可能会在更换硬件时发生变化,这会导致设备 ID 改变
这个方案完全在本地完成,不需要后台服务器支持,适合用于生成基于设备的注册码系统。
7508

被折叠的 条评论
为什么被折叠?



