如果使用者已將 Google 帳戶連結至您的服務,即可透過「已連結帳戶登入」功能一鍵登入 Google。這樣一來,使用者只要按一下就能登入,不必重新輸入使用者名稱和密碼,體驗更順暢。此外,也能降低使用者在服務中建立重複帳戶的機率。
連結帳戶登入功能是 Android 版「One Tap 登入」流程的一部分。也就是說,如果應用程式已啟用「One Tap」功能,您就不必匯入其他程式庫。
本文將說明如何修改 Android 應用程式,以支援連結帳戶登入。
運作方式
- 在「One Tap 登入」流程中選擇顯示已連結的帳戶。
- 如果使用者已登入 Google,並將 Google 帳戶連結至您服務中的帳戶,系統會傳回連結帳戶的 ID 權杖。
- 系統會向使用者顯示「One Tap 登入」提示,並提供使用已連結帳戶登入您服務的選項。
- 如果使用者選擇繼續使用已連結的帳戶,系統會將使用者的 ID 權杖傳回應用程式。您可以在第 2 步中,將這個權杖與傳送至伺服器的權杖進行比對,找出登入的使用者。
設定
設定開發環境
在開發主機上取得最新版 Google Play 服務:
在「SDK 工具」下方,找到「Google Play 服務」。
如果這些套件的狀態不是「已安裝」,請選取這兩個套件,然後按一下「安裝套件」。
設定應用程式
在專案層級的
build.gradle檔案中,同時在buildscript和allprojects區段中加入 Google 的 Maven 存放區。buildscript { repositories { google() } } allprojects { repositories { google() } }將「與 Google 帳戶連結」API 的依附元件新增至模組的應用程式層級 gradle 檔案,通常為
app/build.gradle:dependencies { implementation 'com.google.android.gms:play-services-auth:21.3.0' }
修改 Android 應用程式,支援連結帳戶登入
在連結帳戶登入流程結束時,系統會將 ID 權杖傳回您的應用程式。請先驗證 ID 權杖的完整性,再讓使用者登入。
以下程式碼範例詳細說明如何擷取、驗證 ID 權杖,然後讓使用者登入。
建立活動,接收登入意圖的結果
Kotlin
private val activityResultLauncher = registerForActivityResult( ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode == RESULT_OK) { try { val signInCredentials = Identity.signInClient(this) .signInCredentialFromIntent(result.data) // Review the Verify the integrity of the ID token section for // details on how to verify the ID token verifyIdToken(signInCredential.googleIdToken) } catch (e: ApiException) { Log.e(TAG, "Sign-in failed with error code:", e) } } else { Log.e(TAG, "Sign-in failed") } }Java
private final ActivityResultLauncher<IntentSenderResult> activityResultLauncher = registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), result -> { If (result.getResultCode() == RESULT_OK) { try { SignInCredential signInCredential = Identity.getSignInClient(this) .getSignInCredentialFromIntent(result.getData()); verifyIdToken(signInCredential.getGoogleIdToken()); } catch (e: ApiException ) { Log.e(TAG, "Sign-in failed with error:", e) } } else { Log.e(TAG, "Sign-in failed") } });建立登入要求
Kotlin
private val tokenRequestOptions = GoogleIdTokenRequestOptions.Builder() .supported(true) // Your server's client ID, not your Android client ID. .serverClientId(getString("your-server-client-id") .filterByAuthorizedAccounts(true) .associateLinkedAccounts("service-id-of-and-defined-by-developer", scopes) .build()Java
private final GoogleIdTokenRequestOptions tokenRequestOptions = GoogleIdTokenRequestOptions.Builder() .setSupported(true) .setServerClientId("your-service-client-id") .setFilterByAuthorizedAccounts(true) .associateLinkedAccounts("service-id-of-and-defined-by-developer", scopes) .build()啟動「Sign-In Pending」意圖
Kotlin
Identity.signInClient(this) .beginSignIn( BeginSignInRequest.Builder() .googleIdTokenRequestOptions(tokenRequestOptions) .build()) .addOnSuccessListener{result -> activityResultLauncher.launch(result.pendingIntent.intentSender) } .addOnFailureListener {e -> Log.e(TAG, "Sign-in failed because:", e) }Java
Identity.getSignInClient(this) .beginSignIn( BeginSignInRequest.Builder() .setGoogleIdTokenRequestOptions(tokenRequestOptions) .build()) .addOnSuccessListener(result -> { activityResultLauncher.launch( result.getPendingIntent().getIntentSender()); }) .addOnFailureListener(e -> { Log.e(TAG, "Sign-in failed because:", e); });
驗證 ID 權杖的完整性
使用 Google API 用戶端程式庫
建議您使用 Java Google API 用戶端程式庫,在正式環境中驗證 Google ID 權杖。
Java
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
...
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
// Specify the CLIENT_ID of the app that accesses the backend:
.setAudience(Collections.singletonList(CLIENT_ID))
// Or, if multiple clients access the backend:
//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
.build();
// (Receive idTokenString by HTTPS POST)
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
} else {
System.out.println("Invalid ID token.");
}
GoogleIdTokenVerifier.verify() 方法會驗證 JWT 簽章、aud 權杖附加資訊、iss 權杖附加資訊和 exp 權杖附加資訊。
如需驗證 ID 權杖是否代表 Google Workspace 或 Cloud 機構帳戶,可以檢查 hd 聲明,確認 Payload.getHostedDomain() 方法傳回的網域名稱。