contextBridge
在隔離的上下文之間建立安全、雙向、同步的橋樑
進程:渲染器
下面提供一個範例,說明如何從隔離的預載腳本向渲染器公開 API
// Preload (Isolated World)
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (Main World)
window.electron.doThing()
詞彙表
主世界
「主世界」是您的主要渲染器程式碼在其中執行的 JavaScript 上下文。預設情況下,您在渲染器中載入的頁面會在該世界中執行程式碼。
隔離世界
當您的 webPreferences
中啟用 contextIsolation
時(這是 Electron 12.0.0 以來的預設行為),您的 preload
腳本會在「隔離世界」中執行。您可以在安全性文件中閱讀更多關於上下文隔離及其影響的資訊。
方法
contextBridge
模組具有以下方法
contextBridge.exposeInMainWorld(apiKey, api)
apiKey
字串 - 用於將 API 注入到window
的索引鍵。API 將可在window[apiKey]
上存取。api
任意 - 您的 API,有關此 API 是什麼以及如何運作的更多資訊如下。
contextBridge.exposeInIsolatedWorld(worldId, apiKey, api)
worldId
整數 - 要將 API 注入其中的世界的 ID。0
是預設世界,999
是 Electron 的contextIsolation
功能所使用的世界。使用 999 將會為預載上下文公開物件。我們建議在建立隔離世界時使用 1000+。apiKey
字串 - 用於將 API 注入到window
的索引鍵。API 將可在window[apiKey]
上存取。api
任意 - 您的 API,有關此 API 是什麼以及如何運作的更多資訊如下。
用法
API
提供給exposeInMainWorld
的 api
必須是 Function
、string
、number
、Array
、boolean
或一個物件,其鍵為字串,而值為 Function
、string
、number
、Array
、boolean
或另一個符合相同條件的巢狀物件。
Function
值會被代理到其他上下文中,而所有其他值都會被複製和凍結。API 中傳送的任何資料/原始值都會變成不可變的,而橋樑任一側的更新都不會導致另一側的更新。
下面顯示一個複雜 API 的範例
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing'),
myPromises: [Promise.resolve(), Promise.reject(new Error('whoops'))],
anAsyncFunction: async () => 123,
data: {
myFlags: ['a', 'b', 'c'],
bootTime: 1234
},
nestedAPI: {
evenDeeper: {
youCanDoThisAsMuchAsYouWant: {
fn: () => ({
returnData: 123
})
}
}
}
}
)
下面顯示 exposeInIsolatedWorld
的範例
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInIsolatedWorld(
1004,
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
// Renderer (In isolated world id1004)
window.electron.doThing()
API 函式
您透過 contextBridge
綁定的 Function
值會透過 Electron 代理,以確保上下文保持隔離。這會導致我們在下面概述的一些關鍵限制。
參數/錯誤/傳回類型支援
由於參數、錯誤和傳回值在透過橋樑傳送時會被複製,因此只能使用某些類型。在高層次上,如果您要使用的類型可以序列化和反序列化為相同的物件,它將會運作。為了完整起見,下面包含一個類型支援表
類型 | 複雜性 | 參數支援 | 傳回值支援 | 限制 |
---|---|---|---|---|
字串 | 簡單 | ✅ | ✅ | 不適用 |
數字 | 簡單 | ✅ | ✅ | 不適用 |
布林值 | 簡單 | ✅ | ✅ | 不適用 |
物件 | 複雜 | ✅ | ✅ | 索引鍵必須使用此表中的「簡單」類型來支援。此表中必須支援值。原型修改會被捨棄。傳送自訂類別將會複製值,但不會複製原型。 |
陣列 | 複雜 | ✅ | ✅ | 與 Object 類型相同的限制 |
錯誤 | 複雜 | ✅ | ✅ | 擲出的錯誤也會被複製,這可能會導致錯誤的訊息和堆疊追蹤由於在不同的上下文中擲出而略有變化,並且 Error 物件上的任何自訂屬性將會遺失 |
Promise | 複雜 | ✅ | ✅ | 不適用 |
函式 | 複雜 | ✅ | ✅ | 原型修改會被捨棄。傳送類別或建構函式將無法運作。 |
可複製的類型 | 簡單 | ✅ | ✅ | 請參閱有關可複製類型的連結文件 |
元素 | 複雜 | ✅ | ✅ | 原型修改會被捨棄。傳送自訂元素將無法運作。 |
Blob | 複雜 | ✅ | ✅ | 不適用 |
符號 | 不適用 | ❌ | ❌ | 符號無法在上下文之間複製,因此會被捨棄 |
如果您關心的類型不在上表中,則可能不受支援。
公開 ipcRenderer
嘗試將整個 ipcRenderer
模組作為物件透過 contextBridge
傳送,將會在橋樑的接收端產生一個空物件。完整地傳送 ipcRenderer
可以讓任何程式碼傳送任何訊息,這是一種安全隱憂。若要透過 ipcRenderer
進行互動,請提供如下所示的安全包裝
// Preload (Isolated World)
contextBridge.exposeInMainWorld('electron', {
onMyEventName: (callback) => ipcRenderer.on('MyEventName', (e, ...args) => callback(args))
})
// Renderer (Main World)
window.electron.onMyEventName(data => { /* ... */ })
公開 Node 全域符號
預載腳本可以使用 contextBridge
來讓您的渲染器存取 Node API。上面描述的支援類型表也適用於您透過 contextBridge
公開的 Node API。請注意,許多 Node API 都授予對本機系統資源的存取權。對於您公開給不受信任的遠端內容的全域變數和 API,請務必非常謹慎。
const { contextBridge } = require('electron')
const crypto = require('node:crypto')
contextBridge.exposeInMainWorld('nodeCrypto', {
sha256sum (data) {
const hash = crypto.createHash('sha256')
hash.update(data)
return hash.digest('hex')
}
})