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

總覽

OAuth 式 Google 登入簡化連結會在 OAuth 連結之外新增 Google 登入。這不僅能為 Google 使用者提供流暢的連結體驗,還能啟用帳戶,讓使用者透過自己的 Google 帳戶建立新帳戶。

如要透過 OAuth 和 Google 登入功能連結帳戶,請按照下列一般步驟操作:

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

圖 1. 使用者可透過簡化連結的方式在手機上連結自己的帳戶

簡化連結的相關規定

實作 OAuth 伺服器

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

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

檢查現有的使用者帳戶 (檢查意圖)

使用者表示同意存取其 Google 個人資料後,Google 會傳送一項要求,其中包含對 Google 使用者身分進行簽署的聲明。清單包含使用者 Google 帳戶 ID、名稱和電子郵件地址等資訊。您為專案設定的權杖交換端點會處理該項要求。

如果驗證系統中已有對應的 Google 帳戶,您的權杖交換端點會以 account_found=true 回應。如果 Google 帳戶與現有使用者不相符,您的權杖交換端點會傳回 account_found=false 傳回 HTTP 404 Not Found 錯誤。

這項要求的格式如下:

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&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

您的權杖交換端點必須能夠處理下列參數:

權杖端點參數
intent 針對這些要求,這個參數的值為 check
grant_type 交換的權杖類型。針對這些要求,這個參數的值為 urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JSON Web Token (JWT) 提供已簽署的 Google 使用者身分宣告。JWT 內含使用者 Google 帳戶 ID、名稱和電子郵件地址等資訊。
client_id 您指派給 Google 的用戶端 ID。
client_secret 您指派給 Google 的用戶端密鑰。

如要回應 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 帳戶

請確認下列任一種情況是否成立:

  • 這個 Google 帳戶 ID (位於宣告的 sub 欄位中) 位於使用者資料庫中。
  • 宣告中的電子郵件地址與您的使用者資料庫中的使用者相符。

只要符合其中一個條件,就表示使用者已註冊。在這種情況下,系統會傳回類似以下的回應:

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

{
  "account_found":"true",
}

如果設定中指定的 Google 帳戶 ID 和電子郵件地址均不符合資料庫中的使用者,表示使用者尚未註冊。在這個情況下,您的權杖交換端點需要傳回指定 "account_found": "false" 的 HTTP 404 錯誤,如以下範例所示:

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

{
  "account_found":"false",
}

處理自動連結 (取得意圖)

使用者表示同意存取其 Google 個人資料後,Google 會傳送一項要求,其中包含對 Google 使用者身分進行簽署的聲明。清單包含使用者 Google 帳戶 ID、名稱和電子郵件地址等資訊。您為專案設定的權杖交換端點會處理該項要求。

如果驗證系統中已有對應的 Google 帳戶,您的權杖交換端點就會為使用者傳回憑證。如果 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&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

您的權杖交換端點必須能夠處理下列參數:

權杖端點參數
intent 針對這些請求,這個參數的值為 get
grant_type 交換的權杖類型。針對這些要求,這個參數的值為 urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JSON Web Token (JWT) 提供已簽署的 Google 使用者身分宣告。JWT 內含使用者 Google 帳戶 ID、名稱和電子郵件地址等資訊。
scope 選用:您已設定讓 Google 提出使用者要求的所有範圍。
client_id 您指派給 Google 的用戶端 ID。
client_secret 您指派給 Google 的用戶端密鑰。

如要回應 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 帳戶

請確認下列任一種情況是否成立:

  • 這個 Google 帳戶 ID (位於宣告的 sub 欄位中) 位於使用者資料庫中。
  • 宣告中的電子郵件地址與您的使用者資料庫中的使用者相符。

如果找到使用者的帳戶,請發出存取憑證,並在 HTTPS 回應的內文中傳回 JSON 物件的值,如以下範例所示:

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

  "refresh_token": "REFRESH_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

在某些情況下,根據 ID 符記連結帳戶的使用者可能無法使用。如果發生任何原因,您的符記交換端點必須傳回以 error=linking_error 表示的 HTTP 401 錯誤,如以下範例所示:

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 連結流程完成帳戶連結程序。

透過 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&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET

您的權杖交換端點必須能夠處理下列參數:

權杖端點參數
intent 針對這些請求,這個參數的值為 create
grant_type 交換的權杖類型。針對這些要求,這個參數的值為 urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JSON Web Token (JWT) 提供已簽署的 Google 使用者身分宣告。JWT 內含使用者 Google 帳戶 ID、名稱和電子郵件地址等資訊。
client_id 您指派給 Google 的用戶端 ID。
client_secret 您指派給 Google 的用戶端密鑰。

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,但是此後第三方電子郵件帳戶的所有權可能已更改。

驗證使用者資訊及建立新帳戶

請確認下列任一種情況是否成立:

  • 這個 Google 帳戶 ID (位於宣告的 sub 欄位中) 位於使用者資料庫中。
  • 宣告中的電子郵件地址與您的使用者資料庫中的使用者相符。

如果符合其中一個條件,提示使用者將現有的帳戶與 Google 帳戶連結。如要這麼做,請以指定 error=linking_error 的 HTTP 401 錯誤回應要求,並將使用者的電子郵件地址設為 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 登入新增到其他平台,讓使用者能夠在應用程式的介面上透過 Google 登入。或者,您也可以透過電子郵件向使用者傳送可啟動密碼救援流程的連結,讓使用者能夠設定在其他平台上登入的密碼。

建立程序完成後,請發出存取憑證 並重新整理符記 ,並在 HTTPS 回應的主體中傳回 JSON 物件中的值,如以下範例所示:

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

  "refresh_token": "REFRESH_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

取得 Google API 用戶端 ID

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

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

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

    如果專案沒有網頁應用程式類型的用戶端 ID,請按一下 [建立憑證 > OAuth 用戶端 ID] 來建立。請務必在「Authorized JavaScript origins」(已授權的 JavaScript 來源) 方塊中加入您的網站網域。執行本機測試或開發作業時,必須將「http://localhost」和「http://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. 確認您被重定向到您的平台。