這邊紀錄 Electron App 要怎麼使用 OAuth 取得第三方服務。
OAuth 流程
OAuth 流程網路上已經有很多詳盡資料,這邊就不做詳述;簡單來說步驟是
- 根據需要的權限 ( Scopes ) 需求進入第三方提供的認證網址
- 使用者登入
- 第三方驗證後,提供相關權限
方法一
用 Electron 開啟第三方畫面,並用 onBeforeRequest 攔截資料,取得 token 後,存到記憶體或用 keytar 存到電腦帳號中
const userLogin = () => {
const {
session: { webRequest }
} = authWindow.webContents
const filter: WebRequestFilter = {
urls: ['APP_REDIRECT_URL']
}
const handleRedirectUrl = (url: string) => {
/** 分析 Redirect Url,發出 api 請求 token、refresh token */
}
webRequest.onBeforeRequest(filter, handleRedirectUrl)
authWindow.loadURL(Authentication_URL)
}
/** App 執行當下驗證是否已經有 token,沒有則進入驗證流程 */
app.on('ready', async () => {
try {
await AuthService.refreshTokens()
MainProcess.init()
} catch (error) {
userLogin()
}
})
但這個用法有兩個問題
- Electron 提供的瀏覽器不會更新版本,登入第三方可能會遭拒
- 不夠安全
方法二
使用系統本身的瀏覽器,並用 nodejs http module 建立簡易 server 處理 redirect url
/** render process 載入畫面完成後,驗證 token */
ipcMain.on('on render process finish', async () => {
try {
await AuthService.refreshTokens()
} catch (error) {
MainProcess.setAuthReadyStatus(false)
}
})
/** AuthReadyStatus 為 false 時,顯示登入按鈕 */
ipcMain.on('open:auth', (event, args) => {
login()
})
/** 建立 server,攔截 redirect url 取得 token */
function setServer() {
return new Promise<void>((res, rej) => {
AuthProcess.server = http.createServer(async (request, response) => {
await handleRedirectUrl(
`http://${request.headers.host}${request.url}`
)
response.statusCode = 200
response.setHeader('Content-Type', 'text/html')
response.end(`<h1>Login success.</h1>`)
MainProcess.setAuthReadyStatus(true)
AuthProcess.server.close()
AuthProcess.server = null
})
AuthProcess.server.listen(3000, res)
})
}
/** 用 shell.openExternal 開啟系統瀏覽器 */
function login() {
await setServer()
await shell.openExternal(AuthService.authenticationURL())
}
app.on('ready', MainProcess.init)
這邊可能需要去檢查目前 server port 是否有被占用,另外也可以用 app.setAsDefaultProtocolClient 自動導向 Electron app 本身