3.8 KiB
3.8 KiB
version, last-updated, status
| version | last-updated | status |
|---|---|---|
| 1.1 | 2026-03-05 | implemented |
Device ID 生成方案
概述
为 Electron 客户端生成稳定、安全的设备唯一标识符(deviceId),用于设备识别、授权绑定等场景。
方案
核心公式
deviceId = SHA-256(machineId + appSalt)
machineId:操作系统级机器标识(通过node-machine-id获取原始值)appSalt:应用固定盐值,避免不同应用使用相同 machineId 产生碰撞
实现
import { machineIdSync } from "node-machine-id";
import { createHash } from "crypto";
import * as os from "os";
import log from "electron-log";
const APP_SALT = "qiming-agent";
let cachedDeviceId: string | null = null;
export function getDeviceId(): string {
if (cachedDeviceId) return cachedDeviceId;
let raw: string;
try {
raw = machineIdSync(true);
} catch (e) {
log.warn("[DeviceId] Failed to read machineId, using hostname fallback:", e);
raw = os.hostname();
}
cachedDeviceId = createHash("sha256")
.update(raw + APP_SALT)
.digest("hex");
log.info(`[DeviceId] ${cachedDeviceId}`);
return cachedDeviceId;
}
各平台 machineId 数据源
| 平台 | 数据源 | 说明 |
|---|---|---|
| macOS | ioreg → IOPlatformUUID |
硬件 UUID,无需管理员权限 |
| Windows | 注册表 HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid |
系统安装时生成 |
| Linux | /var/lib/dbus/machine-id |
systemd 机器 ID |
依赖
| 包名 | 版本 | 说明 |
|---|---|---|
node-machine-id |
^1.1.12 | 跨平台机器 ID 读取,零 native 依赖 |
crypto 为 Node.js 内置模块,无需额外安装。
设计要点
1. 稳定性
- 同一台机器每次调用返回相同值
- 进程内缓存,避免重复读取系统命令
2. 安全性
- SHA-256 单向 hash,不暴露原始 machineId
- 加入应用盐值,防止跨应用关联
3. 唯一性
- machineId 由操作系统保证唯一
- 加盐 hash 后不同应用产生不同 deviceId
4. 位置
- 实现在 main process(
src/main/services/下) - renderer 通过 IPC + preload bridge 获取
架构集成
Main Process
├── src/main/services/system/deviceId.ts # 实现 + 缓存 + 日志
├── src/main/services/system/index.ts # re-export
├── src/main/main.ts # 启动时调用并输出日志
└── src/main/ipc/appHandlers.ts # IPC handler
Preload
└── src/preload/index.ts # contextBridge 暴露
Renderer
└── window.electronAPI.app.getDeviceId() # 调用
IPC 通道
// main (appHandlers.ts)
ipcMain.handle("app:getDeviceId", () => getDeviceId());
// preload (index.ts)
app: {
getDeviceId: () => ipcRenderer.invoke("app:getDeviceId"),
}
特性对比(为何选此方案)
| 方案 | 稳定性 | 安全性 | 依赖 | 备注 |
|---|---|---|---|---|
| hash(machineId + salt) | 高 | 高 | 1 个 npm 包 | 选用 |
| 纯 machineId | 高 | 低(暴露原始值) | 1 个 npm 包 | 不推荐 |
| hw-fingerprint(硬件指纹) | 中(换硬件会变) | 高 | 重依赖 systeminformation | 过重 |
| 本地持久化 UUID | 低(删文件会变) | 中 | 无 | 不绑定设备 |
| hash(machineId + randomUUID) | 无(每次不同) | - | - | 错误方案 |
注意事项
- 容器/镜像环境:基于镜像的环境可能共享相同 machine-id,Linux 下可用
dbus-uuidgen重新生成 - Windows 系统更新:MachineGuid 在重大系统更新后极少数情况下可能变化
- macOS 权限:IOPlatformUUID 无需额外权限,区别于 IOPlatformSerialNumber(新版 macOS 受限)
参考: 此方案为 SaaS 客户端常用的设备标识模式