本指南介绍了如何实现“使用 Google 账号登录”,并涵盖以下步骤:
- 为应用添加依赖项。
- 实例化
CredentialManager。 - 创建底部动作条流程。
- 创建按钮流。
- 处理登录响应。
- 处理错误。
- 处理退出账号操作。
为应用添加依赖项
在模块的 build.gradle 文件中,使用最新版本 Credential Manager、Play 服务 Auth和 googleid 声明依赖项:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.7.0-alpha02") implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha02") implementation("com.google.android.libraries.identity.googleid:googleid:<latest version>") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.7.0-alpha02" implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha02" implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>" }
实例化 Credential Manager
使用应用或 activity 上下文创建 CredentialManager 对象。
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
创建底部动作条流程
底部动作条是 Credential Manager 的内置界面。使用此界面可在所有身份验证方法(例如密码、通行密钥和“使用 Google 账号登录”)中打造一致的体验。
为先前已授权的账号配置登录请求
尝试使用 GetGoogleIdOption 发出 Google 登录请求,以检索用户的 Google ID 令牌。
以下代码段会检查账号是否为授权账号。
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(WEB_CLIENT_ID)
.setAutoSelectEnabled(true)
.setNonce(generateSecureRandomNonce())
.build()
请求 googleIdOption 对象的配置如下:
过滤之前已获授权的账号:如需检索之前曾用于登录应用的已获授权账号,请将
setFilterByAuthorizedAccounts设置为true。请注意,
setFilterByAuthorizedAccounts的默认值为true,这意味着底部动作条界面的默认行为是仅显示之前已获授权的账号。设置服务器客户端 ID:设置
setServerClientId参数。webClientId是您在完成前提条件时在 Google Cloud 项目中为 OAuth 设置的 Web 客户端 ID。启用自动登录(可选):如需为回访用户启用自动登录,请使用
setAutoSelectEnabled(true)和setFilterByAuthorizedAccounts(true)。对于应用用户,如果他们之前已经登录,则可以省去不必要的麻烦。只有在满足以下条件时,用户才能自动登录:
- 设备上只有一个授权账号,并且该授权账号之前曾用于登录设备上的应用。设备上有多个已获授权的账号会停用自动登录功能。
- 用户在上一个会话期间未明确退出应用。
- 用户尚未在其 Google 账号设置中停用自动登录功能。
设置 Nonce(可选):如需启用增强型安全性,请为服务器端验证设置 Nonce。为防止重放攻击,您可以添加一个 Nonce,以便使用
setNonce()进行服务器端验证。确保您的服务器端代码验证请求和响应 Nonce 是否相同。如需生成 Nonce,请使用类似于以下函数的函数,该函数会生成指定长度的加密型强随机 Nonce,并使用
Base64对其进行编码:
fun generateSecureRandomNonce(byteLength: Int = 32): String {
val randomBytes = ByteArray(byteLength)
SecureRandom().nextBytes(randomBytes)
return Base64.encodeToString(randomBytes, Base64.NO_WRAP or Base64.URL_SAFE or Base64.NO_PADDING)
}
请求登录
通过调用 getCredential 方法,检查用户在设备上是否拥有已获授权的账号:
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
// Use an activity-based context to avoid undefined system UI
// launching behavior.
val mutableContext = MutableContextWrapper(activityContext)
coroutineScope {
try {
val result = credentialManager.getCredential(
request = request,
context = mutableContext // Use MutableContextWrapper to avoid memory leak during configuration changes
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failures
}
}
配置在没有授权账号可用时的登录请求
如果设备上没有应用授权用户,CredentialManager 会返回 NoCredentialException。在这种情况下,请停用授权账号过滤条件,以便用户可以使用其他账号注册。
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(WEB_CLIENT_ID)
.setNonce(generateSecureRandomNonce())
.build()
接下来,请求登录,方法与您对授权账号的操作类似。
创建按钮流程
如果您希望用户能够在以下情况下使用 Google 账号登录,请使用按钮:
- 用户关闭了 Credential Manager 底部动作条界面。
- 此设备上没有 Google 账号。
- 设备上的现有账号需要重新进行身份验证。
创建按钮界面
虽然您可以使用 Jetpack Compose 按钮执行此操作,但您也可以使用“使用 Google 账号登录”品牌推广指南页面中预先批准的品牌图标。
创建登录流程
使用 GetSignInWithGoogleOption 创建 Google 登录请求,以检索 Google ID 令牌。
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(
serverClientId = WEB_CLIENT_ID
).setNonce(generateSecureRandomNonce())
.build()
接下来,请求登录,方法与底部动作条界面类似。
为底部动作条和按钮创建共享登录函数
如需处理登录,请完成以下步骤:
- 使用 CredentialManager 的
getCredential()函数。如果响应成功,请提取CustomCredential,其类型应为GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL。 使用
GoogleIdTokenCredential.createFrom()方法将该对象转换为GoogleIdTokenCredential。在依赖方服务器上验证凭证。
请确保您妥善处理错误。
fun handleSign(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 the ID for server-side validation.
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 账号,并决定使用其他账号登录。例如,您可以在设置页面中提供此选项。
凭证提供程序可能会存储活跃凭证会话,并使用该会话来限制未来登录请求的登录选项。例如,它可以优先使用有效凭据,而不是任何其他可用凭据。
当用户从应用中退出账号时,请调用 API clearCredentialState() 方法,以从所有凭据提供程序中清除当前用户凭据状态。这会通知所有凭据提供程序,应清除给定应用的所有已存储凭据会话,以便下次为用户提供完整的登录选项。