当前位置: 首页 > news >正文

Electron应用中获取设备唯一ID和系统信息

让我创建一篇关于如何在Electron应用中获取设备唯一ID和系统信息,并在登录时使用这些信息的博客文章。我将确保步骤明确、条理清晰,适合初学者和有经验的开发者。

这篇博客应包含以下部分:

  1. 介绍 - 为什么需要获取设备信息
  2. 前提条件和安装依赖
  3. 主进程(main.js)配置 - 添加IPC处理程序
  4. 预加载脚本(preload.js)配置 - 暴露安全API
  5. 渲染进程(前端Vue组件)使用
  6. 调试技巧和常见问题
  7. 安全和隐私考虑
  8. 总结和进一步阅读

这样的结构应该能全面覆盖这个功能的实现并帮助读者理解每个部分的作用。

在Electron应用中获取设备唯一ID和系统信息

简介

在现代应用程序开发中,获取设备唯一标识和系统信息是一项常见需求,尤其对于需要设备识别、登录验证和用户行为分析的应用。本文将详细讲解如何在Electron应用中实现设备信息获取功能,并将其与登录流程集成。

为什么需要获取设备信息?

  • 设备识别:跟踪和识别用户的不同设备
  • 安全验证:增强账号安全,防止未授权登录
  • 数据分析:了解用户设备分布和使用环境
  • 功能适配:根据系统环境提供定制化功能

前提条件

  • Node.js 和 npm 已安装
  • 基本的Electron应用结构
  • Vue.js前端框架(本文使用Vue 3)

实现步骤

1. 安装必要依赖

首先,我们需要安装node-machine-id库来获取设备唯一ID:

# 在项目的client目录下执行
cd client
npm install node-machine-id --save

2. 配置主进程(main.js)

在Electron的主进程文件中,添加获取系统信息和设备ID的IPC处理函数:

// client/electron/main.jsconst { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const os = require('os')
const { machineIdSync } = require('node-machine-id')// 其他现有代码...// 添加获取系统信息的处理函数
ipcMain.handle('get-system-info', () => {try {const systemInfo = {platform: process.platform,  // 'win32', 'darwin', 'linux'等arch: process.arch,          // 'x64', 'arm64'等osName: os.type(),           // 操作系统类型osVersion: os.release(),     // 操作系统版本hostname: os.hostname(),     // 主机名totalMem: os.totalmem(),     // 总内存(字节)cpuCores: os.cpus().length   // CPU核心数};return systemInfo;} catch (error) {console.error('获取系统信息失败:', error);return {platform: 'unknown',arch: 'unknown',osName: 'unknown',osVersion: 'unknown',hostname: 'unknown'};}
});// 添加获取设备唯一ID的处理函数
ipcMain.handle('get-machine-id', () => {try {// 使用node-machine-id库获取系统唯一IDconst machineId = machineIdSync(true);console.log('生成的machineId:', machineId);return machineId;} catch (error) {console.error('获取设备ID失败:', error);// 生成一个随机ID作为后备方案const fallbackId = 'device-' + Math.random().toString(36).substring(2, 15);return fallbackId;}
});

3. 创建预加载脚本(preload.js)

预加载脚本是连接Electron主进程和渲染进程的桥梁,通过它我们可以安全地暴露主进程API给渲染进程:

// client/preload.jsconst { contextBridge, ipcRenderer } = require('electron');// 调试信息
console.log('preload.js 正在加载...');function logToConsole(message) {console.log(`[preload] ${message}`);
}// 暴露API给渲染进程
contextBridge.exposeInMainWorld('electron', {// 获取系统信息 - 返回PromisegetSystemInfo: async () => {logToConsole('调用getSystemInfo');try {const result = await ipcRenderer.invoke('get-system-info');logToConsole(`getSystemInfo结果: ${JSON.stringify(result)}`);return result;} catch (error) {logToConsole(`getSystemInfo错误: ${error.message}`);throw error;}},// 获取设备ID - 返回PromisegetMachineId: async () => {logToConsole('调用getMachineId');try {const result = await ipcRenderer.invoke('get-machine-id');logToConsole(`getMachineId结果: ${result}`);return result;} catch (error) {logToConsole(`getMachineId错误: ${error.message}`);throw error;}},// 测试API可用性 - 直接返回值testAPI: () => {logToConsole('testAPI被调用');return '测试API可用';},// 应用版本 - 直接返回值getVersion: () => {return '1.0.0';}
});console.log('preload.js 已完成加载');

4. 配置BrowserWindow,确保使用preload.js

main.js中创建窗口时,确保正确配置了preload脚本:

function createWindow() {mainWindow = new BrowserWindow({width: 1200,height: 800,// 其他窗口配置...webPreferences: {nodeIntegration: false,contextIsolation: true,webSecurity: false,preload: path.join(__dirname, '../preload.js')  // 预加载脚本路径}});// 加载应用...
}

5. 在Vue组件中使用设备信息

在登录组件(如LoginView.vue)中,添加获取设备信息的功能:

// client/src/views/LoginView.vue<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useAppStore } from '@/stores/useAppStore';const router = useRouter();
const appStore = useAppStore();// 表单数据
const username = ref('admin');
const password = ref('admin');
const remember = ref(false);
const errorMsg = ref('');
const isLoading = ref(false);// 设备信息
const deviceId = ref('');
const systemInfo = ref(null);// 检查API是否可用
const checkElectronAPI = () => {console.log('测试Electron API是否可用...');if (window.electron) {console.log('window.electron 对象存在');// 检查异步函数是否存在console.log('getSystemInfo 存在?', typeof window.electron.getSystemInfo === 'function');console.log('getMachineId 存在?', typeof window.electron.getMachineId === 'function');} else {console.log('window.electron 对象不存在,可能在浏览器环境或preload.js未加载');}
};// 获取系统信息和设备ID
const getSystemInfo = async () => {console.log('开始获取系统信息...');try {// 检查electron对象是否可用if (typeof window.electron !== 'undefined') {console.log('检测到Electron环境');try {// 获取系统信息console.log('正在调用getSystemInfo...');const info = await window.electron.getSystemInfo();console.log('获取到系统信息:', info);systemInfo.value = info;// 获取设备IDconsole.log('正在调用getMachineId...');const id = await window.electron.getMachineId();console.log('获取到设备ID:', id);deviceId.value = id;// 保存到localStoragelocalStorage.setItem('system_info', JSON.stringify(info));localStorage.setItem('device_id', id);return true;} catch (err) {console.error('调用Electron API出错:', err);return false;}} else {console.log('非Electron环境,使用Web备选方案');// Web环境下的备选方案if (!localStorage.getItem('device_id')) {const randomId = 'web-' + Math.random().toString(36).substring(2, 15);localStorage.setItem('device_id', randomId);deviceId.value = randomId;} else {deviceId.value = localStorage.getItem('device_id');}const webInfo = {platform: 'web',userAgent: navigator.userAgent,language: navigator.language};systemInfo.value = webInfo;localStorage.setItem('system_info', JSON.stringify(webInfo));return true;}} catch (error) {console.error('获取系统信息总体失败:', error);return false;}
};// 登录处理函数
const handleLogin = async () => {// 表单验证if (!username.value || !password.value) {errorMsg.value = !username.value ? '请输入用户名' : '请输入密码';return;}try {isLoading.value = true;errorMsg.value = '';// 确保有设备IDif (!deviceId.value) {console.log('登录前获取设备ID');await getSystemInfo();}// 组装登录数据const loginData = {username: username.value,password: password.value,deviceId: deviceId.value || localStorage.getItem('device_id'),systemInfo: systemInfo.value || JSON.parse(localStorage.getItem('system_info') || '{}')};// 调用登录API  
};// 组件挂载时获取系统信息
onMounted(() => {console.log('组件已挂载,获取系统信息');checkElectronAPI();getSystemInfo();
});
</script>

调试技巧

使用控制台测试API

在浏览器开发者工具的控制台中,可以直接测试API:

// 检查electron对象是否存在
console.log('window.electron 对象存在?', !!window.electron);// 测试调用API
if (window.electron) {// 测试异步APIwindow.electron.getSystemInfo().then(info => {console.log('系统信息:', info);localStorage.setItem('system_info', JSON.stringify(info));}).catch(err => {console.error('获取系统信息失败:', err);});window.electron.getMachineId().then(id => {console.log('设备ID:', id);localStorage.setItem('device_id', id);}).catch(err => {console.error('获取设备ID失败:', err);});
}

检查localStorage

在开发者工具的Application/Storage标签中,查看localStorage是否正确保存了设备信息:

  • system_info
  • device_id

常见问题解决

1. Cannot find module ‘node-machine-id’

确保已正确安装依赖:

npm install node-machine-id --save

2. window.electron对象为undefined

可能的原因:

  • preload.js路径配置错误
  • contextIsolation设置不正确
  • preload.js中没有正确暴露API

解决方案:检查BrowserWindow的webPreferences配置,确保preload路径正确。

3. 调用API时出现"不是函数"错误

区分同步和异步API:

  • 同步API (如testAPI):直接调用 const result = window.electron.testAPI()
  • 异步API (如getSystemInfo):使用Promise await window.electron.getSystemInfo()

安全注意事项

  1. 不要暴露敏感API:只暴露渲染进程需要的API,遵循最小权限原则
  2. 处理异常:所有API调用都应有适当的错误处理
  3. 保护用户隐私:仅收集必要的设备信息,并告知用户
  4. 安全存储:避免在localStorage中存储敏感信息,考虑使用加密

总结

通过本文介绍的方法,可以在Electron应用中安全地获取设备唯一ID和系统信息,并将其与登录流程集成。这种方式遵循了Electron的安全最佳实践,使用上下文隔离和预加载脚本来安全地暴露主进程API给渲染进程。

正确实现后,能够识别用户设备,增强安全性,并提供更好的用户体验。此功能对于需要设备绑定、多设备管理和用户行为分析的应用特别有用。

参考文档

  1. Electron安全性文档
  2. node-machine-id库文档
  3. Electron上下文隔离
  4. Electron IPC通信

相关文章:

Electron应用中获取设备唯一ID和系统信息

让我创建一篇关于如何在Electron应用中获取设备唯一ID和系统信息&#xff0c;并在登录时使用这些信息的博客文章。我将确保步骤明确、条理清晰&#xff0c;适合初学者和有经验的开发者。 这篇博客应包含以下部分&#xff1a; 介绍 - 为什么需要获取设备信息前提条件和安装依赖…...

文件上传漏洞:upload-labs靶场11-20

目录 pass-11 pass-12 pass-13 pass-14 pass-15 pass-16 pass-17 pass-18 pass-19 pass-20 pass-11 分析源代码 &#xff0c;发现上传文件的存放路径可控 if(isset($_POST[submit])){$ext_arr array(jpg,png,gif);$file_ext substr($_FILES[upload_file][name],st…...

国产化板卡设计原理图:2330-基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡

基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡 一、板卡概述 本板卡基于 FPGAJFM7K325T 芯片&#xff0c;pin_to_pin兼容FPGAXC7K410T-2FFG900 &#xff0c;支持PCIeX8、64bit DDR3容量2GByte&#xff0c;HPC的FMC连接器&#xff0c;板卡支持PXIE标准协议&#xff0c;其中XJ3…...

使用Open WebUI下载的模型文件(Model)默认存放在哪里?

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Ollama部署LLM专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年2月21日21点21分 &#x1f004;️文章质量&#xff1a;95分 文章目录 使用CMD安装存放位置 默认存放路径 Open WebUI下…...

FPGA 配置原理

用户编程控制的FPGA 是通过加载比特位流配置内部的存储单元实现的。该存储单元就是所谓的配置单元&#xff0c;它必须在器件上电后进行配置&#xff0c;从而设置查找表&#xff08;LUT&#xff09;的属性、连线方式、IOB 电压标准和其它的用户设计。 1.配置帧 以Xilinx 公司的…...

企业级虚拟化数据库基础平台自动化部署项目

一、项目简介及准备工作 1.1.虚拟化平台简介 1.1.1.ESXi 8 是什么&#xff1f; 定义&#xff1a; ESXi 8 是 VMware 推出的最新版本 裸机虚拟化管理程序&#xff08;Hypervisor&#xff09;&#xff0c;属于 VMware vSphere 产品线的核心组件。 核心功能&#xff1a; 在物理…...

关于elementui的时间组件与后端时间和oracle数据库时间的对应格式

前端&#xff1a; <el-date-pickerv-model"formInline.startTime"type"date"value-format"yyyy-MM-dd"placeholder"选择日期"> </el-date-picker> 后端&#xff1a; private String startTime; private String endTime…...

一周学会Flask3 Python Web开发-WTForms表单验证

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们可以通过WTForms表单类属性的validators属性来实现表单验证。 常用的WTForms验证器 验证器说明DataRequired(messageNo…...

qt open3dBPA重建

qt open3dBPA重建 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionBPA_triggered();//bpa重建 void MainWindow::...

Unity游戏开发中的网格简化与LOD技术(Mesh Simplification LOD)

在Unity游戏开发中&#xff0c;网格简化&#xff08;Mesh Simplification&#xff09;和LOD&#xff08;Level of Detail&#xff09;技术是优化渲染性能的关键手段&#xff0c;尤其在处理复杂场景和高精度模型时至关重要。以下是一套系统的实现方案与优化策略&#xff1a; 一、…...

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

纯html文件实现目录和文档关联

目录结构 效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>项目结题报告</title><style lang"scss">::-webkit-scrollbar {width: 6px;height: 6px;}::-webkit-scro…...

C# | 委托 | 事件 | 异步

委托&#xff08;Delegate&#xff09;和事件&#xff08;Event&#xff09; 在C#和C中&#xff0c;委托&#xff08;Delegate&#xff09;与事件&#xff08;Event&#xff09;以及函数对象&#xff08;Function Object&#xff09;是实现回调机制或传递行为的重要工具。虽然…...

数据结构——顺序表与链表

1. 基础介绍 1、线性结构&#xff1a; 如果一个数据元素序列满足&#xff1a; &#xff08;1&#xff09;除第一个和最后一个数据元素外&#xff0c;每个数据元素只有一个前驱数据元素和一个后继数据元素&#xff1b; &#xff08;2&#xff09;第一个数据元素没有前驱数据…...

【uniapp】图片添加canvas水印

目录 需求&背景实现地理位置添加水印 ios补充 需求&背景 需求&#xff1a;拍照后给图片添加水印, 水印包含经纬度、用户信息、公司logo等信息。 效果图&#xff1a; 方案&#xff1a;使用canvas添加水印。 具体实现&#xff1a;上传图片组件是项目里现有的&#xff…...

ElementUI 级联选择器el-cascader启用选择任意一级选项,选中后关闭下拉框

1、启用选择任意一级选项 在 el-cascader 标签上加上配置项&#xff1a; :props"{ checkStrictly: true }"例如&#xff1a; <el-cascaderref"selectedArrRef"v-model"selectedArr":options"optionsList":props"{ checkStri…...

【音视频】ffplay常用命令

一、 ffplay常用命令 -x width&#xff1a;强制显示宽度-y height&#xff1a;强制显示高度 强制以 640*360的宽高显示 ffplay 2.mp4 -x 640 -y 360 效果如下 -fs 全屏显示 ffplay -fs 2.mp4效果如下&#xff1a; -an 禁用音频&#xff08;不播放声音&#xff09;-vn 禁…...

5人3小时复刻Manus?开源OpenManus项目全解剖,我的DeepSeek股票报告这样诞生

大家好,我是大 F,深耕AI算法十余年,互联网大厂技术岗。分享AI算法干货、技术心得。 更多文章可关注《大模型理论和实战》、《DeepSeek技术解析和实战》,一起探索技术的无限可能! OpenManus是什么 1. 项目背景 OpenManus 是由 MetaGPT 核心团队仅用 3 小时复刻而成的开源…...

【Python运维】用Python自动化AWS资源管理:利用boto3实现高效管理S3桶和EC2实例

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着云计算的普及,AWS(Amazon Web Services)已经成为许多企业和开发者首选的云平台。为了提高工作效率,自动化管理AWS资源成为了一个热…...

django各种mixin用法

在 Django 中,Mixin 是一种用于扩展类功能的设计模式。通过 Mixin,可以在不修改原有类的情况下,为其添加新的方法或属性。Django 中的 Mixin 广泛应用于视图(View)、表单(Form)、模型(Model)等组件中。以下是 Django 中常见 Mixin 的用法和示例: 一、视图(View)中的…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案

问题描述&#xff1a;iview使用table 中type: "index",分页之后 &#xff0c;索引还是从1开始&#xff0c;试过绑定后台返回数据的id, 这种方法可行&#xff0c;就是后台返回数据的每个页面id都不完全是按照从1开始的升序&#xff0c;因此百度了下&#xff0c;找到了…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL

ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...