上下文隔離功能將確保您的 預(yù)加載
腳本 和 Electron的內(nèi)部邏輯 運(yùn)行在所加載的 ?webcontent
? 網(wǎng)頁(yè) 之外的另一個(gè)獨(dú)立的上下文環(huán)境里。 這對(duì)安全性很重要,因?yàn)樗兄谧柚咕W(wǎng)站訪問(wèn) Electron 的內(nèi)部組件 和 您的預(yù)加載腳本可訪問(wèn)的高等級(jí)權(quán)限的API 。
這意味著,實(shí)際上,您的預(yù)加載腳本訪問(wèn)的 window
對(duì)象并不是網(wǎng)站所能訪問(wèn)的對(duì)象。 例如,如果您在預(yù)加載腳本中設(shè)置 window.hello = 'wave'
并且啟用了上下文隔離,當(dāng)網(wǎng)站嘗試訪問(wèn)window.hello
對(duì)象時(shí)將返回 undefined。
自 Electron 12 以來(lái),默認(rèn)情況下已啟用上下文隔離,并且它是 所有應(yīng)用程序推薦的安全設(shè)置。
沒(méi)有上下文隔離,從預(yù)加載腳本提供API時(shí),經(jīng)常會(huì)使用?
window.X = apiObject
? 那么現(xiàn)在呢?
在渲染進(jìn)程中,預(yù)加載腳本暴露給已加載的頁(yè)面 API 是一個(gè)常見的使用方式。 當(dāng)上下文隔離時(shí),您的預(yù)加載腳本可能會(huì)暴露一個(gè)常見的全局window
對(duì)象給渲染進(jìn)程。 此后,您可以從中添加任意的屬性到預(yù)加載在腳本。
// 上下文隔離禁用的情況下使用預(yù)加載
window.myAPI = {
doAThing: () => {}
}
doAThing()
函數(shù)可以在渲染進(jìn)程中直接使用。
// 在渲染器進(jìn)程使用導(dǎo)出的 API
window.myAPI.doAThing()
Electron 提供一種專門的模塊來(lái)無(wú)阻地幫助您完成這項(xiàng)工作。 ?contextBridge
? 模塊可以用來(lái)安全地從獨(dú)立運(yùn)行、上下文隔離的預(yù)加載腳本中暴露 API 給正在運(yùn)行的渲染進(jìn)程。 API 還可以像以前一樣,從 window.myAPI
網(wǎng)站上訪問(wèn)。
// 在上下文隔離啟用的情況下使用預(yù)加載
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
doAThing: () => {}
})
// 在渲染器進(jìn)程使用導(dǎo)出的 API
window.myAPI.doAThing()
請(qǐng)閱讀 contextBridge
的文檔,以全面了解其限制。 例如,您不能在 contextBridge 中暴露原型或者 Symbol。
單單開啟和使用 contextIsolation
并不直接意味著您所做的一切都是安全的。 例如,此代碼是 不安全的。
// ? 錯(cuò)誤使用
contextBridge.exposeInMainWorld('myAPI', {
send: ipcRenderer.send
})
它直接暴露了一個(gè)沒(méi)有任何參數(shù)過(guò)濾的高等級(jí)權(quán)限 API 。 這將允許任何網(wǎng)站發(fā)送任意的 IPC 消息,這不會(huì)是你希望發(fā)生的。 相反,暴露進(jìn)程間通信相關(guān) API 的正確方法是為每一種通信消息提供一種實(shí)現(xiàn)方法。
// ? 正確使用
contextBridge.exposeInMainWorld('myAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})
如果您正在使用 TypeScript 構(gòu)建 Electron 應(yīng)用程序,您需要給通過(guò) context bridge 暴露的 API 添加類型。 渲染進(jìn)程的 window
對(duì)象將不會(huì)包含正確擴(kuò)展類型,除非給其添加了 類型聲明。
例如,在這個(gè) preload.ts
腳本中:
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})
您可以創(chuàng)建一個(gè) renderer.d.ts
類型聲明文件,并且全局增強(qiáng) Window
接口。
export interface IElectronAPI {
loadPreferences: () => Promise<void>,
}
declare global {
interface Window {
electronAPI: IElectronAPI
}
}
以上所做皆是為了確保在您編寫渲染進(jìn)程的腳本時(shí), TypeScript 編譯器將會(huì)知曉electronAPI
合適地在您的全局window
對(duì)象中
window.electronAPI.loadPreferences()
更多建議: