关联的账号登录功能可让已将 Google 账号与您的服务相关联的用户一键登录。这样可以改善用户体验,因为用户只需点击一下即可登录,而无需重新输入用户名和密码。这还可以降低用户在您的服务中创建重复账号的几率。
关联的账号登录功能是 Android 的一键登录流程的一部分。这意味着,如果您的应用已启用“一键式”功能,则无需导入单独的库。
在本文档中,您将了解如何修改 Android 应用以支持关联的账号登录。
工作原理
- 您可以在一键式登录流程中选择显示关联的账号。
- 如果用户已登录 Google,并已将其 Google 账号与您服务中的账号相关联,系统会针对关联的账号返回 ID 令牌。
- 系统会向用户显示一键式登录提示,其中包含使用关联的账号登录您的服务的选项。
- 如果用户选择继续使用关联的账号,系统会将用户的 ID 令牌返回到您的应用。您可以将此令牌与在第 2 步中发送到服务器的令牌进行匹配,以识别已登录的用户。
设置
设置您的开发环境
在开发主机上获取最新的 Google Play 服务:
- 打开 Android SDK 管理器。
在 SDK Tools 下,找到 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 令牌以及随后登录用户的步骤。
创建一个 activity 来接收登录 intent 的结果
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()
启动“登录待处理”intent
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 客户端库
在生产环境中验证 Google ID 令牌时,建议使用 Java Google API 客户端库。
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 组织账号,可以通过检查 Payload.getHostedDomain()
方法返回的域名来验证 hd
声明。