使用 OAuth 和 Google 登入功能簡化連結程序

總覽

以 OAuth 為基礎的 Google 登入簡化連結除了 OAuth 連結之外,還新增了 Google 登入。這不僅為 Google 使用者提供流暢的連結體驗,還可啟用帳戶建立功能,讓使用者透過 Google 帳戶在您的服務中建立新帳戶。

如要執行 OAuth 與 Google 登入的帳戶連結作業,請按照下列一般步驟操作:

  1. 首先,要求使用者同意存取 Google 個人資料。
  2. 使用設定檔中的資訊,檢查使用者帳戶是否存在。
  3. 如果是現有使用者,請連結帳戶。
  4. 如果您在驗證系統中找不到相符的 Google 使用者,請驗證 Google 收到的 ID 憑證。接著,您就能根據 ID 憑證中包含的個人資料建立使用者。
這個圖表顯示使用者使用簡化連結流程來連結 Google 帳戶的步驟。第一個螢幕截圖顯示了使用者要如何選擇要連結的應用程式。第二張螢幕截圖可讓使用者確認服務上是否有既有的帳戶。第三個螢幕截圖可讓使用者選取要連結的 Google 帳戶。第四張螢幕截圖顯示了將應用程式與 Google 帳戶建立連結的確認訊息。第五張螢幕截圖則顯示 Google app 中成功連結的使用者帳戶。

圖 1. 使用者可透過帳戶連結,在使用者的手機上進行帳戶連結

簡化連結相關規定

實作 OAuth 伺服器

您的憑證交換端點必須支援 checkcreateget 意圖。下圖顯示了透過帳戶連結流程完成的步驟,並指出系統呼叫不同意圖的時機:

  1. 使用者在驗證系統中是否有帳戶?(使用者選取 [是] 或 [否] 可決定)
    1. 是 :使用者是否使用與 Google 帳戶相關聯的電子郵件地址登入平台?(使用者選取 [是] 或 [否] 可決定)
      1. 是: 使用者驗證系統中是否有相符的帳戶?(系統會呼叫 check intent 以確認)
        1. 是:系統會呼叫 get intent,如果取得意圖傳回成功,就會連結帳戶。
        2. 否 :建立新帳戶?(使用者選取 [是] 或 [否] 可決定)
          1. 是:系統會呼叫 create intent,且成功建立建立意圖傳回結果時,帳戶的連結成功。
          2. 否 :網路 OAuth 流程已觸發,系統會將使用者導向至瀏覽器,同時提供其他電子郵件的連結。
      2. 否:系統會觸發 Web OAuth 流程,並將使用者導向至瀏覽器,同時提供選擇其他電子郵件地址的選項。
    2. 否 :使用者驗證系統中是否有相符的帳戶?(系統會呼叫 check intent 以確認)
      1. 是:系統會呼叫 get intent,如果取得意圖傳回成功,就會連結帳戶。
      2. 否:如果呼叫的意圖傳回成功,系統就會呼叫 create intent,並連結帳戶。

檢查現有用戶帳戶(檢查意圖)

在用戶同意訪問其 Google 個人資料後,Google 會發送一個請求,其中包含對 Google 用戶身份的簽名聲明。該斷言包含的信息包括用戶的 Google 帳戶 ID、姓名和電子郵件地址。為您的項目配置的令牌交換端點處理該請求。

如果相應的谷歌帳戶是在驗證系統已經存在,你的令牌交換終結響應account_found=true 。如果谷歌帳戶沒有現有用戶相匹配,您的令牌交換終結返回一個HTTP 404 Not Found錯誤account_found=false

該請求具有以下形式:

POST /token HTTP/1.1
Host: oauth2.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=check&assertion=JWT&scope=SCOPES

您的令牌交換端點必須能夠處理以下參數:

令牌端點參數
intent對於這些請求,這個參數的值是check
grant_type正在交換的令牌類型。對於這些請求,這個參數的值是urn:ietf:params:oauth:grant-type:jwt-bearer
assertion一個 JSON Web 令牌 (JWT),它提供了對 Google 用戶身份的簽名斷言。 JWT 包含的信息包括用戶的 Google 帳戶 ID、姓名和電子郵件地址。

要在應對check意圖的請求,您的令牌交換,端點必須執行以下步驟:

  • 驗證和解碼 JWT 斷言。
  • 檢查 Google 帳戶是否已存在於您的身份驗證系統中。
驗證並解碼JWT斷言

您可以使用針對您的語言JWT解碼庫來驗證和解碼JWT斷言。使用Google的JWKPEM格式的公鑰來驗證令牌的簽名。

解碼後,JWT斷言類似於以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了驗證令牌的簽名外,還要驗證斷言的頒發者( iss字段)為https://accounts.google.com ,受眾( aud字段)是您分配的客戶端ID,並且令牌尚未過期( exp場地)。

使用emailemail_verifiedhd字段,您可以確定Google是否託管電子郵件地址並對其具有權威性。如果Google具有權威性,則當前已知該用戶為合法帳戶所有者,您可以跳過密碼或其他挑戰方法。否則,可以使用這些方法在鏈接之前驗證帳戶。

Google具有權威性的情況:

  • email後綴為@gmail.com ,這是一個Gmail帳戶。
  • email_verified為true並且設置了hd ,這是一個G Suite帳戶。

用戶可以在不使用Gmail或G Suite的情況下註冊Google帳戶。如果email不包含@gmail.com後綴,並且hd缺失,則Google不具有權威性,建議使用密碼或其他挑戰方法來驗證用戶。當Google在創建Google帳戶時最初驗證了用戶時, email_verfied也可能為true,但是此後第三方電子郵件帳戶的所有權可能已更改。

檢查您的身份驗證系統中是否已存在 Google 帳戶

檢查是否滿足以下任一條件:

  • 該谷歌帳戶ID,在斷言的發現sub場,是在你的用戶數據庫。
  • 斷言中的電子郵件地址與用戶數據庫中的用戶匹配。

如果任一條件為真,則用戶已經註冊。在這種情況下,返回如下響應:

HTTP/1.1 200 Success
Content-Type: application/json;charset=UTF-8

{
  "account_found":"true",
}

如果斷言中指定的 Google 帳戶 ID 和電子郵件地址都與您數據庫中的用戶不匹配,則該用戶尚未註冊。在這種情況下,您的令牌交換端點需要用HTTP 404錯誤,指定回复"account_found": "false" ,如下面的例子:

HTTP/1.1 404 Not found
Content-Type: application/json;charset=UTF-8

{
  "account_found":"false",
}

處理自動鏈接(獲取意圖)

在用戶同意訪問其 Google 個人資料後,Google 會發送一個請求,其中包含對 Google 用戶身份的簽名聲明。該斷言包含的信息包括用戶的 Google 帳戶 ID、姓名和電子郵件地址。為您的項目配置的令牌交換端點處理該請求。

如果您的身份驗證系統中已存在相應的 Google 帳戶,則您的令牌交換端點會為用戶返回一個令牌。如果谷歌帳戶沒有現有用戶相匹配,您的令牌交換終結返回linking_error錯誤和可選login_hint

該請求具有以下形式:

POST /token HTTP/1.1
Host: oauth2.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=get&assertion=JWT&scope=SCOPES

您的令牌交換端點必須能夠處理以下參數:

令牌端點參數
intent對於這些請求,這個參數的值是get
grant_type正在交換的令牌類型。對於這些請求,這個參數的值是urn:ietf:params:oauth:grant-type:jwt-bearer
assertion一個 JSON Web 令牌 (JWT),它提供了對 Google 用戶身份的簽名斷言。 JWT 包含的信息包括用戶的 Google 帳戶 ID、姓名和電子郵件地址。
scope可選:任何作用域,你已經配置了谷歌從用戶的請求。

要在響應get意圖的要求,你的令牌交換,端點必須執行以下步驟:

  • 驗證和解碼 JWT 斷言。
  • 檢查 Google 帳戶是否已存在於您的身份驗證系統中。
驗證並解碼JWT斷言

您可以使用針對您的語言JWT解碼庫來驗證和解碼JWT斷言。使用Google的JWKPEM格式的公鑰來驗證令牌的簽名。

解碼後,JWT斷言類似於以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了驗證令牌的簽名外,還要驗證斷言的頒發者( iss字段)為https://accounts.google.com ,受眾( aud字段)是您分配的客戶端ID,並且令牌尚未過期( exp場地)。

使用emailemail_verifiedhd字段,您可以確定Google是否託管電子郵件地址並對其具有權威性。如果Google具有權威性,則當前已知該用戶為合法帳戶所有者,您可以跳過密碼或其他挑戰方法。否則,可以使用這些方法在鏈接之前驗證帳戶。

Google具有權威性的情況:

  • email後綴為@gmail.com ,這是一個Gmail帳戶。
  • email_verified為true並且設置了hd ,這是一個G Suite帳戶。

用戶可以在不使用Gmail或G Suite的情況下註冊Google帳戶。如果email不包含@gmail.com後綴,並且hd缺失,則Google不具有權威性,建議使用密碼或其他挑戰方法來驗證用戶。當Google在創建Google帳戶時最初驗證了用戶時, email_verfied也可能為true,但是此後第三方電子郵件帳戶的所有權可能已更改。

檢查您的身份驗證系統中是否已存在 Google 帳戶

檢查是否滿足以下任一條件:

  • 該谷歌帳戶ID,在斷言的發現sub場,是在你的用戶數據庫。
  • 斷言中的電子郵件地址與用戶數據庫中的用戶匹配。

如果發現用戶的賬號,發出的訪問令牌,並在您的HTTPS響應的主體在下面的例子中JSON對象返回的值,比如:

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

在某些情況下,用戶基於 ID 令牌的帳戶鏈接可能會失敗。如果它這樣做以任何理由,你的令牌交換端點需要用HTTP回复401錯誤指定error=linking_error ,如下例所示:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

當谷歌收到401錯誤響應linking_error ,谷歌會將用戶帶到你的授權端點login_hint作為參數。用戶使用瀏覽器中的 OAuth 鏈接流程完成帳戶鏈接。

通過 Google 登錄處理帳戶創建(創建意圖)

當用戶需要在您的服務上創建帳戶時,Google 會向您的令牌交換端點發出請求,指定intent=create

該請求具有以下形式:

POST /token HTTP/1.1
Host: oauth2.example.com
Content-Type: application/x-www-form-urlencoded

response_type=token&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=SCOPES&intent=create&assertion=JWT

您的令牌交換端點必須能夠處理以下參數:

令牌端點參數
intent對於這些請求,此參數的值為create
grant_type正在交換的令牌類型。對於這些請求,此參數的值為urn:ietf:params:oauth:grant-type:jwt-bearer
assertion一個 JSON Web 令牌 (JWT),它提供了對 Google 用戶身份的簽名斷言。 JWT 包含的信息包括用戶的 Google 帳戶 ID、姓名和電子郵件地址。

assertion參數中的 JWT 包含用戶的 Google 帳戶 ID、姓名和電子郵件地址,您可以使用它們在您的服務上創建新帳戶。

要響應create意圖請求,您的令牌交換端點必須執行以下步驟:

  • 驗證和解碼 JWT 斷言。
  • 驗證用戶信息並創建新帳戶。
驗證並解碼JWT斷言

您可以使用針對您的語言JWT解碼庫來驗證和解碼JWT斷言。使用Google的JWKPEM格式的公鑰來驗證令牌的簽名。

解碼後,JWT斷言類似於以下示例:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

除了驗證令牌的簽名外,還要驗證斷言的頒發者( iss字段)為https://accounts.google.com ,受眾( aud字段)是您分配的客戶端ID,並且令牌尚未過期( exp場地)。

使用emailemail_verifiedhd字段,您可以確定Google是否託管電子郵件地址並對其具有權威性。如果Google具有權威性,則當前已知該用戶為合法帳戶所有者,您可以跳過密碼或其他挑戰方法。否則,可以使用這些方法在鏈接之前驗證帳戶。

Google具有權威性的情況:

  • email後綴為@gmail.com ,這是一個Gmail帳戶。
  • email_verified為true並且設置了hd ,這是一個G Suite帳戶。

用戶可以在不使用Gmail或G Suite的情況下註冊Google帳戶。如果email不包含@gmail.com後綴,並且hd缺失,則Google不具有權威性,建議使用密碼或其他挑戰方法來驗證用戶。當Google在創建Google帳戶時最初驗證了用戶時, email_verfied也可能為true,但是此後第三方電子郵件帳戶的所有權可能已更改。

驗證用戶信息並創建新帳戶

檢查是否滿足以下任一條件:

  • 在斷言的sub字段中找到的 Google 帳戶 ID 位於您的用戶數據庫中。
  • 斷言中的電子郵件地址與用戶數據庫中的用戶匹配。

如果任一條件為真,則提示用戶將其現有帳戶與其 Google 帳戶相關聯。為此,請使用 HTTP 401 錯誤響應請求,指定error=linking_error並將用戶的電子郵件地址作為login_hint 。以下是示例響應:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

當 Google 收到帶有linking_error的 401 錯誤響應時,Google 會將用戶發送到您的授權端點, login_hint作為參數。用戶使用瀏覽器中的 OAuth 鏈接流程完成帳戶鏈接。

如果兩個條件都不成立,請使用 JWT 中提供的信息創建一個新用戶帳戶。新帳戶通常沒有設置密碼。建議您將 Google Sign-In 添加到其他平台,以使用戶能夠通過您的應用程序界面使用 Google 登錄。或者,您可以通過電子郵件向用戶發送啟動密碼恢復流程的鏈接,以允許用戶設置密碼以在其他平台上登錄。

創建完成後,發出訪問令牌 並在 HTTPS 響應的正文中返回 JSON 對像中的值,如下例所示:

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

取得您的 Google API 用戶端 ID

在帳戶連結註冊程序期間,您必須提供 Google API 用戶端 ID。

如要使用完成 OAuth 連結步驟時建立的專案,取得您的 API 用戶端 ID。如要這樣做,請完成下列步驟:

  1. 開啟 Google API 控制台的「憑證」頁面。
  2. 建立或選取 Google API 專案。

    如果您的專案沒有網路應用程式類型的用戶端 ID,請按一下 [Create credentials > OAuth Client ID] 建立憑證。請務必在「授權的 JavaScript 來源」方塊中,加入您網站的網域。執行本機測試或開發作業時,您必須將 http://localhosthttp://localhost:<port_number> 新增至「Authorized JavaScript origins」(已獲授權的 JavaScript 來源) 欄位。

驗證實作

您可以通過使用驗證實現的OAuth 2.0遊樂場工具。

在工具中,執行以下步驟:

  1. 單擊配置打開的OAuth 2.0配置窗口。
  2. OAuth流場中,選擇客戶端
  3. OAuth端點字段中,選擇自定義
  4. 在相應字段中指定您的 OAuth 2.0 端點和您分配給 Google 的客戶端 ID。
  5. 步驟1部分,不要選擇任何谷歌範圍。相反,將此字段留空或鍵入對您的服務器有效的範圍(如果不使用 OAuth 範圍,則輸入任意字符串)。當您完成後,單擊授權的API。
  6. 步驟2步驟3段,完成OAuth 2.0流程和驗證每個步驟按預期工作。

您可以通過驗證您的實現谷歌帳戶鏈接演示工具。

在工具中,執行以下步驟:

  1. 點擊登錄在與谷歌按鈕。
  2. 選擇您要關聯的帳戶。
  3. 輸入服務標識。
  4. (可選)輸入您將請求訪問的一個或多個範圍。
  5. 單擊開始演示
  6. 出現提示時,確認您可以同意並拒絕鏈接請求。
  7. 確認您被重定向到您的平台。