OAuth 連結類型支援兩種符合業界標準的 OAuth 2.0 流程,分別是隱含和授權程式碼流程。
在隱式程式碼流程中,Google 會在使用者的瀏覽器中開啟您的授權端點。成功登入後,系統會將長期存取權杖傳回 Google。從現在起,每次透過 Google 助理傳送給您動作的要求中,都會包含這個存取權杖。
在授權碼流程中,您需要兩個端點:
- 授權端點,該端點負責將登入 UI 提供給未登入的使用者,並以簡碼授權代碼的形式,記錄使用者要求的存取權。
- 權杖交換端點,負責以下兩種交換類型:
- 交換長期更新權杖的授權碼和短期存取權杖。這項交換作業會在使用者完成帳戶連結流程時進行。
- 對短期存取權杖交換交換憑證。當 Google 需要新的存取權杖,因為更新權杖已過期時,就會發生此交換行為。
雖然隱含程式碼流程的實作方式較簡單,但 Google 建議使用隱含流程發布的存取權杖不會過期,因為若權杖與隱含流程搭配使用,就會強制使用者重新連結帳戶。如果基於安全考量而需要權杖過期,您應該考慮改用授權碼流程。
實作 OAuth 帳戶連結
設定專案
如要將專案設為使用 OAuth 帳戶連結功能,請按照下列步驟操作:
- 開啟「Actions Console」,然後選取要使用的專案。
- 按一下「開發」分頁標籤,然後選擇「帳戶連結」。
- 啟用「帳戶連結」旁的切換鈕。
- 在「建立帳戶」部分中,選取「否,我只想允許在我的網站上建立帳戶」。
在「連結類型」中,選取「OAuth」OAuth和「隱含」OAuth。
在「客戶資訊」部分中:
- 將值指派給「Actions to Google」的用戶端 ID,即可識別來自 Google 的要求。
- 插入授權和權杖交換端點的網址。
- 點按「儲存」。
實作 OAuth 伺服器
為了支援 OAuth 2.0 隱含流程,您的服務會透過 HTTPS 提供授權端點。這個端點會負責驗證及取得使用者的同意聲明,取得資料存取權。授權端點代表尚未登入的使用者登入使用者介面,並記錄對於要求存取權的同意。
當您的動作需要呼叫服務的其中一個已授權 API 時,Google 會使用此端點取得使用者授權,讓他們代表他們呼叫這些 API。
Google 發起的一般 OAuth 2.0 隱含流程工作階段如下:
- Google 會在使用者的瀏覽器中開啟授權端點。如果使用者尚未登入,則請使用者登入;如果他們尚未授予權限,則授權 Google 使用您的 API 存取他們的資料。
- 您的服務會建立存取權杖,並透過將使用者的瀏覽器重新導向回 Google,使其傳回附加在要求中的存取權杖,藉此將權杖傳回 Google。
- Google 會呼叫服務的 API,並在每個要求中附加存取權杖。您的服務會驗證存取權杖是否已授予 Google 存取 API 的授權,然後完成 API 呼叫。
處理授權要求
當您的動作需要透過 OAuth2 隱含流程執行帳戶連結時,Google 會透過含有下列參數的要求,將使用者導向您的授權端點:
授權端點參數 | |
---|---|
client_id |
您指派給 Google 的用戶端 ID。 |
redirect_uri |
您將回應傳送至此要求的網址。 |
state |
傳遞至 Google 的簿記值在重新導向 URI 中維持不變。 |
response_type |
回應中要傳回的值類型。若為 OAuth 2.0 隱含流程,回應類型一律為 token 。 |
舉例來說,如果您在 https://myservice.example.com/auth
取得授權端點,要求看起來可能會像這樣:
GET https://myservice.example.com/auth?client_id=GOOGLE_CLIENT_ID&redirect_uri=REDIRECT_URI&state=STATE_STRING&response_type=token
如要讓授權端點處理登入要求,請按照下列步驟操作:
驗證
client_id
和redirect_uri
值,避免將存取權授予未預期或設定錯誤的用戶端應用程式:- 確認
client_id
與您指派給 Google 的用戶端 ID 相符。 - 確認
redirect_uri
參數指定的網址形式如下:https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
YOUR_PROJECT_ID 是 Actions 主控台「Project settings」(專案設定) 頁面上的 ID。
- 確認
檢查使用者是否已登入您的服務。如果使用者尚未登入,請完成服務的登入或註冊流程。
產生 Google 用來存取 API 的存取權杖。存取權杖可以是任何字串值,但權杖必須專門代表使用者和用戶端,且不得猜測。
傳送 HTTP 回應,將使用者的瀏覽器重新導向至
redirect_uri
參數指定的網址。在網址片段中加入下列所有參數:access_token
:您剛剛產生的存取權杖token_type
:字串bearer
state
:原始要求中的未修改狀態值。以下是結果網址示例:https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID#access_token=ACCESS_TOKEN&token_type=bearer&state=STATE_STRING
Google 的 OAuth 2.0 重新導向處理常式會收到存取權杖,並確認 state
值並未變更。Google 取得服務的存取權杖之後,Google 會透過 AppRequest,將權杖附加至後續的呼叫動作。
啟動驗證流程
使用帳戶登入輔助程式意圖啟動驗證流程。下列程式碼片段說明如何在 Dialogflow 和 Actions SDK 中傳送回應,以使用此輔助程式。
Dialogflow:
const {dialogflow, SignIn} = require('actions-on-google'); const app = dialogflow({ // REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT clientId: CLIENT_ID, }); // Intent that starts the account linking flow. app.intent('Start Signin', (conv) => { conv.ask(new SignIn('To get your account details')); });
@ForIntent("Start Signin") public ActionResponse text(ActionRequest request) { ResponseBuilder rb = getResponseBuilder(request); return rb.add(new SignIn().setContext("To get your account details")).build(); }
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "PLACEHOLDER" } } ] }, "userStorage": "{\"data\":{}}", "systemIntent": { "intent": "actions.intent.SIGN_IN", "data": { "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec", "optContext": "To get your account details" } } } }, "outputContexts": [ { "name": "/contexts/_actions_on_google", "lifespanCount": 99, "parameters": { "data": "{}" } } ] }
Actions SDK:
const {actionssdk, SignIn} = require('actions-on-google'); const app = actionssdk({ // REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT clientId: CLIENT_ID, }); // Intent that starts the account linking flow. app.intent('actions.intent.TEXT', (conv) => { conv.ask(new SignIn('To get your account details')); });
@ForIntent("actions.intent.TEXT") public ActionResponse text(ActionRequest request) { ResponseBuilder rb = getResponseBuilder(request); return rb.add(new SignIn().setContext("To get your account details")).build(); }
{ "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "PLACEHOLDER" } } ] } }, "possibleIntents": [ { "intent": "actions.intent.SIGN_IN", "inputValueData": { "@type": "type.googleapis.com/google.actions.v2.SignInValueSpec", "optContext": "To get your account details" } } ] } ], "conversationToken": "{\"data\":{}}", "userStorage": "{\"data\":{}}" }
處理資料存取要求
如果 Google 助理要求包含存取權杖,請先檢查存取權杖是否有效 (且未過期),然後從資料庫中擷取相關聯的使用者帳戶。