對話動作功能將於 2023 年 6 月 13 日淘汰。詳情請參閱「對話動作已淘汰」。

使用 Google 登入功能連結帳戶

使用者和 Google 助理的 Google 登入能為使用者和開發人員提供最簡單快速的使用者體驗,以便連結帳戶及建立帳戶。您的動作可在對話時要求存取使用者的 Google 個人資料,包括使用者名稱、電子郵件地址和個人資料相片。

你可以使用設定檔資訊,在動作中建立個人化的使用者體驗。如果您在其他平台上有應用程式,而且應用程式採用 Google 登入功能,那麼您也可以找出現有使用者的帳戶並連結至該帳戶、建立新帳戶,以及建立直接與使用者溝通的管道。

若要透過 Google 登入執行帳戶連結,您必須要求使用者同意存取其 Google 個人資料。然後,您會使用設定檔中的使用者資訊 (例如電子郵件地址) 來識別系統中的使用者。

實作 Google 登入帳戶連結

按照下一節的步驟,將 Google 登入帳戶連結至您的動作。

設定專案

若要將專案設定為使用 Google 登入帳戶連結,請按照下列步驟操作:

  1. 開啟 Actions 主控台並選取專案。
  2. 按一下「開發」分頁標籤,然後選擇「帳戶連結」
  3. 啟用「帳戶連結」旁的切換按鈕。
  4. 在「建立帳戶」部分中,選取「是」
  5. 在「連結類型」中選取「Google 登入」

  6. 開啟「Client Information」(客戶資訊),然後記下 Google 核發至您的動作的用戶端 ID 值。

  7. 按一下「儲存」

設計驗證流程的語音使用者介面

檢查使用者是否已通過驗證,並開始帳戶連結流程

  1. Actions Console 中開啟 Actions Builder 專案。
  2. 建立新的場景,開始在動作中連結帳戶:
    1. 按一下「情境」
    2. 按一下「新增」圖示來新增場景。
  3. 在新建立的情境中,按一下「Conditions」(條件) 圖示。
  4. 新增條件,檢查與對話相關聯的使用者是否為已驗證使用者。如果檢查失敗,則動作無法在對話期間連結帳戶,並且應重新提供不需要連結帳戶的功能。
    1. 在「Condition」(條件) 下方的 Enter new expression 欄位中,輸入下列邏輯: user.verificationStatus != "VERIFIED"
    2. 在「轉換」下方,選取不需要帳戶連結的場景,或只能進入訪客模式的進入點。

  1. 按一下「條件」的「新增」圖示
  2. 新增條件,如果使用者沒有相關聯的身分,請觸發帳戶連結流程。
    1. 在「Condition」(條件) 下方的 Enter new expression 欄位中,輸入下列邏輯: user.verificationStatus == "VERIFIED"
    2. 在「轉換」下方選取「帳戶連結」系統情境。
    3. 按一下「儲存」

儲存後,系統會將名為 <SceneName>_AccountLinking 的新帳戶連結系統專案新增至專案。

自訂帳戶連結情境

  1. 在「情境」下方,選取帳戶連結系統情境。
  2. 按一下「傳送提示」,並新增簡短的說明,向使用者說明動作必須存取其身分的原因 (例如「如要儲存偏好設定」)。
  3. 按一下「儲存」

  1. 在「條件」下方,按一下「如果使用者成功完成帳戶連結作業」
  2. 設定當使用者同意連結帳戶時,流程要繼續的方式。例如,呼叫 Webhook 以處理任何必要的自訂商業邏輯,然後切換回來源情境。
  3. 按一下「儲存」

  1. 在「條件」下方,按一下「使用者取消或關閉帳戶連結」
  2. 設定當使用者不同意連結帳戶時,流程應繼續。例如,傳送確認訊息,並重新導向至提供不需要帳戶連結功能的場景。
  3. 按一下「儲存」

  1. 在「條件」下方,按一下「如果發生系統或網路錯誤」
  2. 設定是否因系統或網路錯誤而無法完成帳戶連結流程。例如,傳送確認訊息,並重新導向至提供不需要帳戶連結功能的場景。
  3. 按一下「儲存」

存取後端中的設定檔資訊

使用者授權您的動作存取他們的 Google 設定檔之後,您會收到一個 Google ID 憑證,其中包含每個後續要求的動作時使用者的 Google 個人資料。

如要存取使用者的設定檔資訊,您必須先按照下列步驟驗證並解碼權杖:

  1. 為您的語言使用 JWT 解碼程式庫來解碼權杖,並使用 Google 的公開金鑰 (JWKPEM 格式) 來驗證權杖簽章。
  2. 確認權杖的核發者 (解碼權杖中的 iss 欄位) 為 https://accounts.google.com,且目標對象 (已解碼權杖中的 aud 欄位) 是 Google 核發至動作的用戶端 ID 的值,也就是在 Actions 控制台中指派給您的專案。

以下是解碼權杖的範例:

{
  "sub": 1234567890,        // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The token's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Client ID assigned to your Actions project
  "iat": 233366400,         // Unix timestamp of the token's creation time
  "exp": 233370000,         // Unix timestamp of the token's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "locale": "en_US"
}

如果使用 Node.js 的 Actions on Google Fulfillment 資料庫,它會為您驗證及解碼權杖,並為您提供設定檔內容的存取權,如以下程式碼片段所示。

...
const app = conversation({
  // REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT
  clientId: CLIENT_ID,
});
...
// Invoked on successful completion of account linking flow, check if we need to
// create a Firebase user.
app.handle('linkAccount', async conv => {
  let payload = conv.headers.authorization;
  if (payload) {
  // Get UID for Firebase auth user using the email of the user
    const email = payload.email;
    if (!conv.user.params.uid && email) {
      try {
        conv.user.params.uid = (await auth.getUserByEmail(email)).uid;
      } catch (e) {
        if (e.code !== 'auth/user-not-found') {
          throw e;
        }
        // If the user is not found, create a new Firebase auth user
        // using the email obtained from Google Assistant
        conv.user.params.uid = (await auth.createUser({email})).uid;
      }
    }
  }
});

處理資料存取要求

如要處理資料存取要求,只需確認資料庫中已有 Google ID 權杖宣告的使用者。以下程式碼片段範例說明瞭如何查看 Firestore 資料庫中是否已有使用者的訂單:

...
app.handle('Place_Order', async conv => {
  const order = conv.session.params.order;
  const userDoc = dbs.user.doc(conv.user.params.uid);
  const orderHistory = userDoc.collection("orderHistory");
  if (orderHistory) {
    // Order history exists, so the user already placed an order.
    // Update counter for order type.
    await orderHistory.doc(order).update({ count: admin.firestore.FieldValue.increment(1)});
  } else {
    // First order they place
    await orderHistory.doc(order).set({ option: order, count: 1});
    options.forEach(opt => {
      if (opt != order) {
        orderHistory.doc(opt).set({ option: opt, count: 0});
      }
    });
  }
  return conv.add(`Your ${order} has been placed. ` +
      'Thanks for using Boba Bonanza, see you soon!');
});