「使用 Google 帳戶登入」功能可協助您快速整合使用者驗證機制與 Android 應用程式。使用者可以利用 Google 帳戶登入應用程式、提供同意聲明,並安全地與應用程式分享個人資料。Android 的 Credential Manager Jetpack 程式庫可順暢進行整合,使用單一 API 在各種 Android 裝置上提供一致的體驗。
本文件會逐步引導您實作 Android 中的「使用 Google 帳戶登入」功能、如何設定「使用 Google 帳戶登入」按鈕 UI,以及設定專為應用程式設計的一鍵註冊和登入體驗。為順利遷移裝置,「使用 Google 帳戶登入」功能支援自動登入功能,「使用 Google 帳戶登入」功能支援 Android、iOS 和網路介面的跨平台特性,可協助您在任何裝置上提供應用程式的登入存取權。
如要設定「使用 Google 帳戶登入」功能,請按照下列兩個主要步驟操作:
將「使用 Google 帳戶登入」功能設為 Credential Manager 底部功能表 UI 的選項。您可以設定自動提示使用者登入。如果您已實作密碼金鑰或密碼,可以同時要求所有相關的憑證類型,讓使用者不必記住先前用來登入的選項。
在應用程式的 UI 中加入「使用 Google 帳戶登入」按鈕。「使用 Google 帳戶登入」按鈕可方便使用者透過現有 Google 帳戶註冊或登入 Android 應用程式。如果使用者關閉底部功能表 UI,或明確想使用自己的 Google 帳戶註冊及登入,就會點選「使用 Google 帳戶登入」按鈕。對開發人員來說,這意味著使用者更容易上手,也能減少註冊期間的阻礙。
本文說明如何使用 Google ID 輔助程式庫,整合「使用 Google 帳戶登入」按鈕和底部功能表對話方塊與 Credential Manager API。
設定 Google API 控制台專案
- 在 API 控制台開啟專案;如果您還沒有專案,請先建立專案。
- 在 OAuth 同意畫面上,確認所有資訊皆完整正確。
- 確認您的應用程式具有正確的應用程式名稱、應用程式標誌和應用程式首頁。這些值會在使用者註冊時,於「使用 Google 帳戶登入」同意畫面顯示,以及第三方應用程式和服務畫面。
- 請確認您已指定應用程式隱私權政策和服務條款的網址。
- 如果您尚未在「憑證」頁面中,為應用程式建立 Android 用戶端 ID,請先建立。您需要指定應用程式的套件名稱和 SHA-1 簽名。
- 前往「Credentials」(憑證) 頁面。
- 按一下「Create credentials」(建立憑證) >「OAuth client ID」(OAuth 用戶端 ID)。
- 選取「Android」應用程式類型。
- 如果您尚未在「憑證」頁面中建立新的「網頁應用程式」用戶端 ID,請先建立一個。您可以暫時忽略「已授權的 JavaScript 來源」和「已授權的重新導向 URI」欄位。這個用戶端 ID 會用來識別與 Google 驗證服務通訊的後端伺服器。
- 前往「Credentials」(憑證) 頁面。
- 按一下「Create credentials」(建立憑證) >「OAuth client ID」(OAuth 用戶端 ID)。
- 選取網頁應用程式類型。
宣告依附元件
在模組的 build.gradle 檔案中,使用最新版的 Credential Manager 宣告依附元件:
dependencies {
// ... other dependencies
implementation "androidx.credentials:credentials:<latest version>"
implementation "androidx.credentials:credentials-play-services-auth:<latest version>"
implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}
將 Google 登入要求例項化
如要開始實作,請建立 Google 登入要求例項。請使用 GetGoogleIdOption
擷取使用者的 Google ID 權杖。
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(WEB_CLIENT_ID)
.setAutoSelectEnabled(true)
.setNonce(<nonce string to use when generating a Google ID token>)
.build()
首先,使用設為 true
的 setFilterByAuthorizedAccounts
參數呼叫 API,檢查使用者是否有先前曾用於登入應用程式的帳戶。使用者可以選擇登入的可用帳戶。
如果沒有可用的已授權的 Google 帳戶,系統應提示使用者使用任一可用帳戶註冊。方法是再次呼叫 API,並將 setFilterByAuthorizedAccounts
設為 false
,藉此提示使用者。進一步瞭解如何註冊。
為回訪者啟用自動登入功能 (建議使用)
開發人員應為透過單一帳戶註冊的使用者啟用自動登入功能。這樣跨裝置都能提供流暢的使用體驗,尤其是在裝置遷移期間,使用者無須重新輸入憑證即可快速重新取得帳戶存取權。對您的使用者而言,這可以讓他們在先前已登入的情況下,免去了不必要的不便。
如要啟用自動登入功能,請使用 setAutoSelectEnabled(true)
。只有在符合下列條件時,您才能自動登入:
- 有一個與要求相符的憑證,可以是 Google 帳戶或密碼,且這個憑證與 Android 裝置上的預設帳戶相符。
- 使用者未明確登出。
- 使用者未在 Google 帳戶設定中停用自動登入功能。
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(WEB_CLIENT_ID)
.setAutoSelectEnabled(true)
.setNonce(<nonce string to use when generating a Google ID token>)
.build()
實作自動登入功能時,請務必正確處理登出,讓使用者在明確登出應用程式後隨時都能選擇適當的帳戶。
設定 Nonce 可提升安全性
為提升登入安全性並避免重送攻擊,請新增 setNonce
,在每項要求中加入 Nonce。進一步瞭解如何產生 Nonce。
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(WEB_CLIENT_ID)
.setAutoSelectEnabled(true)
.setNonce(<nonce string to use when generating a Google ID token>)
.build()
建立「使用 Google 帳戶登入」流程
設定「使用 Google 帳戶登入」流程的步驟如下:
- 將
GetCredentialRequest
執行個體化,然後使用addCredentialOption()
新增先前建立的googleIdOption
,以擷取憑證。 - 將這項要求傳遞至
getCredential()
(Kotlin) 或getCredentialAsync()
(Java) 呼叫,擷取使用者可用的憑證。 - API 成功後,請擷取保留
GoogleIdTokenCredential
資料結果的CustomCredential
。 CustomCredential
的類型應等於GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL
的值。請使用GoogleIdTokenCredential.createFrom
方法,將物件轉換為GoogleIdTokenCredential
。如果轉換成功,請擷取
GoogleIdTokenCredential
ID 並進行驗證,然後在伺服器上驗證憑證。如果轉換作業因
GoogleIdTokenParsingException
失敗,您可能需要更新使用 Google 帳戶登入資料庫的版本。找出所有無法辨識的自訂憑證類型。
val request: GetCredentialRequest = Builder()
.addCredentialOption(googleIdOption)
.build()
coroutineScope.launch {
try {
val result = credentialManager.getCredential(
request = request,
context = activityContext,
)
handleSignIn(result)
} catch (e: GetCredentialException) {
handleFailure(e)
}
}
fun handleSignIn(result: GetCredentialResponse) {
// Handle the successfully returned credential.
val credential = result.credential
when (credential) {
// Passkey credential
is PublicKeyCredential -> {
// Share responseJson such as a GetCredentialResponse on your server to
// validate and authenticate
responseJson = credential.authenticationResponseJson
}
// Password credential
is PasswordCredential -> {
// Send ID and password to your server to validate and authenticate.
val username = credential.id
val password = credential.password
}
// GoogleIdToken credential
is CustomCredential -> {
if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
// Use googleIdTokenCredential and extract id to validate and
// authenticate on your server.
val googleIdTokenCredential = GoogleIdTokenCredential
.createFrom(credential.data)
} catch (e: GoogleIdTokenParsingException) {
Log.e(TAG, "Received an invalid google id token response", e)
}
} else {
// Catch any unrecognized custom credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
}
觸發「使用 Google 帳戶登入」按鈕流程
如要觸發「使用 Google 帳戶登入」按鈕流程,請使用 GetSignInWithGoogleOption
(而非 GetGoogleIdOption
):
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder()
.setServerClientId(WEB_CLIENT_ID)
.setNonce(<nonce string to use when generating a Google ID token>)
.build()
請依照以下程式碼範例說明處理傳回的 GoogleIdTokenCredential
。
fun handleSignIn(result: GetCredentialResponse) {
// Handle the successfully returned credential.
val credential = result.credential
when (credential) {
is CustomCredential -> {
if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
// Use googleIdTokenCredential and extract id to validate and
// authenticate on your server.
val googleIdTokenCredential = GoogleIdTokenCredential
.createFrom(credential.data)
} catch (e: GoogleIdTokenParsingException) {
Log.e(TAG, "Received an invalid google id token response", e)
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
}
將 Google 登入要求例項化後,請採用「使用 Google 帳戶登入」一節所述的類似方式啟動驗證流程。
為新使用者啟用註冊功能 (建議)
「使用 Google 帳戶登入」功能可讓使用者輕鬆輕觸幾下,透過您的應用程式或服務建立新帳戶。
如果找不到已儲存的憑證 (getGoogleIdOption
未傳回任何 Google 帳戶),請提示使用者註冊。首先,請檢查 setFilterByAuthorizedAccounts(true)
是否有先前用過的帳戶。如果找不到,請提示使用者使用 setFilterByAuthorizedAccounts(false)
以自己的 Google 帳戶註冊
例子:
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(SERVER_CLIENT_ID)
.build()
將 Google 註冊要求例項化後,請啟動驗證流程。如果使用者不想使用 Google 註冊,請考慮使用自動填入服務或密碼金鑰建立帳戶。
處理登出動作
當使用者登出應用程式時,請呼叫 API clearCredentialState()
方法,清除所有憑證提供者目前的使用者憑證狀態。這會通知所有憑證提供者,告知系統應清除指定應用程式的任何已儲存憑證工作階段。
憑證提供者可能會儲存執行中的憑證工作階段,並用於限制日後取得憑證呼叫的登入選項。例如,其優先順序可能會優先使用有效的憑證,而非其他任何可用的憑證。當使用者明確登出應用程式,並在下次取得完整的登入選項時,您應呼叫這個 API,讓提供者清除任何已儲存的憑證工作階段。