Call一個Google Workspace API之前,到底還要做多少事?🤨
沒關係,告訴自己,把這一切設置好以後
未來就全部交給🦕Deno幫我自動跑腳本~
接續昨天(Day26),已經開好了GCP專案,接著我需要先取得access token,才有權限使用Google Sheets API。
用Deno執行TypeScript腳本,向GCP申請access token,並以JSON格式存放於專案目錄內。
透過瀏覽器下載Service account key file (JSON format):
https://console.cloud.google.com/welcome?project=<project-name>
這樣我就準備好一份JSON檔案,它就好比我的機器人的身分證明文件。
接下來要做的是,我想透過一些行政手續,向Google OAuth伺服器申請臨時的Google Sheets API使用權限,也就是access token,並存放於.env/
目錄:[^2]
const OUTPUT_PATH = "./.env/gcp-token.json";
由於我希望這個流程可以透過腳本自動化,所以我這裡採用JWT(JSON Web Token)流程。[^3] 這裡我使用Google的Google Auth Library for Node.js套件,它提供了JWT
這個class,它封裝了完整的行政流程,我不需要搞懂流程細節,就可以透過它取得token:
import { JWT } from "npm:google-auth-library@10.3.0";
這個腳本我使用Deno跑,可以不需要手動安裝套件,直接在路徑上標註版本即可,相比於Node.js省去了一個配置步驟。
接著,我使用JWT
創造一個instance,填入兩個文件:
keyFile
scopes
readonly
權限。const client = new JWT({
keyFile: "./keys/service-account.json",
scopes: ["https://www.googleapis.com/auth/spreadsheets.readonly"],
});
然後,透過getAccessToken
方法,就會自動幫我們跑行政流程,並取得token:
const accessToken = await client.getAccessToken();
最後,把token轉成JSON:
const jsonString = JSON.stringify(accessToken, null, 2);
await Deno.writeTextFile(OUTPUT_PATH, jsonString);
console.log(`Saved GCP token to ${OUTPUT_PATH}`);
這樣,就可以讓Deno跑這個腳本:
deno run --allow-net --allow-write --allow-read --allow-env ./denoScripts/get-gcp-token.ts
JWT
instance讀取service account key fileJWT
instance依序讀取:
GOOGLE_SDK_NODE_LOGGING
HTTPS_PROXY
HTTP_PROXY
JWT
instance向Google OAuth伺服器發送HTTP POST請求Deno.writeTextFile
我向Google公司承租了一間圖書室,我請代理人去圖書室查閱某本書並複印部分頁面。
代理人透過Google公司提供的自動製卡機(class JWT
),在機器上掃描員工證(service account key file),填入權限需求後,機器就製造了一個能臨時進入圖書室的門禁卡(access token)。
由於自動製卡機只認員工證,不認員工本人,所以必須小心保管好員工證;同樣的,雖然門禁卡只有一小時期限,但弄丟的話,誰都可以在這段期間進去我的圖書室。
實際上,跑完整個流程的是🦕Deno,他借用代理人的員工證,而代理人還躺在Google雲端上。
基於iThome鐵人賽活動的其中一個目標是推廣中文寫作,這兩天撰文時,我重新辦了一個新Google帳號跑一次中文介面,一時還找不到下載金鑰的地方哈哈哈😅
如果是在公司,我應該不會想用Deno跑腳本,畢竟那是速度與堪用更重要的商務場景。現在回顧覺得當時休假日真的挺chill的,由於Deno的安全性設計,讓JWT執行過程更透明,我可以慢吞吞地稍微了解Google的這個JWT封裝依序在背後做了哪些事、我再一步步同意。
OK,今天就先這樣,我要出門去感受西門町的週六夜晚啦~掰!
[^1]: 和《實作回顧:doGet(下)》一樣,我當時是在prebuild階段使用,所以我直接把金鑰存在專案目錄內,並確定金鑰不會被push到GitHub。就資安上,GCP官方文件則有建議的更佳實作方式。
[^2]: 其實讀者不必將token存放於目錄內,call API時直接附加在fetcher上即可。由於當時我是第一次實作,所以想看一下具體會拿到什麼。
[^3]: JWT廣義來說一個開放標準:RFC7519,由HEADER.PAYLOAD.SIGNATURE
三段的base64編碼構成。由於我沒有要實作API,而僅僅是使用API,所以我只了解到這裡。想進一步了解的讀者,可以閱讀Spongeさん於2019年鐵人賽的這幾篇文章。