如何在electron中安全的使用nodejs
在简单的接触了electron了之后,大家可能都很疑惑,这不就是一个套壳吗,electron可不只能做到这些,如果要开发一个桌面应用端, 不可避免的需要一些IO操作等, 仅依赖JavaScript是远远不够的, electron 是基于 chromium 和 Node.js 构建应用的, 那么我们需要怎么去操作Node呢
webPreferences
在 BrowserWindow 中, 我们能传递一个配置参数 webPreferences,它的可配置项:
- nodeIntegration:是否集成node.js,默认为false
- contextIsolation:上下文隔离,默认为true
- preload:指定预加载的js文件绝对路径
看起来我们似乎只要把nodeIntegration,contextIsolation配置为true和false即可,但是这是非常不安全的一种行为, 在electron中,它更推荐我们使用preload中操作 node,我们在项目根目录下继续创建一个preload.js 通过修改main.js, 把之前使用的生命周期试验给删除掉,仅保留必须的平台差异化处理的生命周期, 接着配置preload,这里需要注意的是,preload值为一个绝对路径,我们需要使用node中的path去处理,此时我们的 main.js 如下:
const { app, BrowserWindow, webContents } = require('electron')
const path = require('node:path')
const createWindows = () => {
const win = new BrowserWindow({
width: 1280,
height: 800,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'preLoad.js'),
},
})
win.loadFile('index.html')
win.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindows()
// 仅 macOS 支持
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindows()
}
})
})
app.on('window-all-closed', () => {
// 对于 Mac 系统, 关闭窗口时并不会直接退出应用, 此时需要我们来手动处理
if (process.platform === 'darwin') {
console.log('close')
app.quit()
}
})
这时我们的nodejs代码就可以写在 preload.js中了。简单试验一下,在preLoad.js中输入如下代码
// proLoad.js
console.log(process.platform)
此时打开控制台就能读取到自己电脑的操作系统了,不过仅仅在preLoad.js文件中使用node对开发者而言还是不够的
contextBridge
electron提供了一个apicontextBridge ,contextBridge 在 Electron 中用于在主进程和渲染进程之间建立安全的通信通道,它提供的主要 API 有:
-
contextBridge.exposeInMainWorld(apiKey, api)
apiKeystring - 将 API 挂载到window的键。 API 将可通过window[apiKey]访问。apiany - 你的 API可以是什么样的以及它是如何工作的相关信息如下。
contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)
worldIdInteger - 要注入 API 的 world 的 ID。0是默认 world,999的 world 被 Electron 的contextIsolation使用。 使用 999 would 为 preload 上下文暴露对象。 我们建议使用 1000+ 来创建隔离的 world。apiKeystring - 将 API 注入到window的键。 API 将可通过window[apiKey]访问。apiany - 你的 API可以是什么样的以及它是如何工作的相关信息如下。
那么我们就知道了, 此时我们可以先试试在preLoad.js中通过exposeInMainWorld暴露一个api看看能否访问到
// preLoad.js
const { contextBridge } = require('electron')
const fs = require('path')
console.log(process.platform)
console.log(fs)
contextBridge.exposeInMainWorld('callNode', {
platform: process.platform
})
新建一个renderer文件夹,新建一个app.js文件,index.html中引入这个app.js,我们是在在app.js中通过window访问callNode
/renderer/app.js
console.log(window.callNode)
electron通过window把我们定义的key-value挂载到window,使得我们可以通过 window这个全局对象去访问我们暴露的值
总体来说,contextBridge 是 Electron 多进程通信的未来方向,使用它可以构建更安全的应用。