使用 Google 帳戶登入可協助您快速將使用者驗證功能整合至 Android 應用程式。使用者可以使用 Google 帳戶登入您的應用程式、提供同意聲明,並安全地將個人資料與您的應用程式分享。Android 的 Credential Manager Jetpack 程式庫可讓這項整合作業順利進行,並透過單一 API 在各 Android 裝置上提供一致的體驗。
本文將引導您在 Android 應用程式中實作「使用 Google 帳戶登入」功能,說明如何設定「使用 Google 帳戶登入」按鈕 UI,以及如何設定應用程式最佳化 One Tap 註冊和登入體驗。為了順利進行裝置遷移,使用 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 同意畫面頁面中,確認所有資訊完整且正確無誤。
- 在「憑證」頁面中,為應用程式建立 Android 用戶端 ID (如果尚未建立)。您必須指定應用程式的套件名稱和 SHA-1 簽名。
- 前往「憑證」頁面。
- 依序點選「建立憑證」>「OAuth 用戶端 ID」。
- 選取「Android」應用程式類型。
- 在「憑證」頁面中,建立新的「網頁應用程式」用戶端 ID (如果尚未建立)。您可以先忽略「Authorized JavaScript Origins」和「Authorized redirect URIs」欄位。當後端伺服器與 Google 驗證服務通訊時,這個用戶端 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()
首先,請呼叫 API,並將 setFilterByAuthorizedAccounts
參數設為 true
,檢查使用者是否有任何帳戶曾用於登入您的應用程式。使用者可以選擇要登入哪個帳戶。
如果沒有可授權的 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 the ID to validate and
// authenticate on your server.
val googleIdTokenCredential = GoogleIdTokenCredential
.createFrom(credential.data)
// You can use the members of googleIdTokenCredential directly for UX
// purposes, but don't use them to store or control access to user
// data. For that you first need to validate the token:
// pass googleIdTokenCredential.getIdToken() to the backend server.
GoogleIdTokenVerifier verifier = ... // see validation instructions
GoogleIdToken idToken = verifier.verify(idTokenString);
// To get a stable account identifier (e.g. for storing user data),
// use the subject ID:
idToken.getPayload().getSubject()
} 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(WEB_CLIENT_ID)
.build()
將 Google 註冊要求例項化後,請啟動驗證流程。如果使用者不想使用「使用 Google 帳戶登入」功能註冊,建議您為應用程式進行自動填入功能最佳化。使用者建立帳戶後,建議您將他們加入密碼金鑰,做為建立帳戶的最後步驟。
處理登出
當使用者登出應用程式時,請呼叫 API clearCredentialState()
方法,清除所有憑證提供者的目前使用者憑證狀態。這會通知所有憑證提供者,應清除特定應用程式的任何已儲存憑證工作階段。
憑證提供者可能已儲存有效的憑證工作階段,並用於限制日後的 get-credential 呼叫登入選項。舉例來說,系統可能會將有效憑證優先於其他可用的憑證。當使用者明確登出應用程式,並希望在下次登入時取得完整的登入選項時,您應呼叫此 API,讓供應商清除任何儲存的憑證工作階段。