このガイドでは、「Google でログイン」を実装する方法について説明します。次の手順について解説します。
- アプリに依存関係を追加する。
CredentialManagerをインスタンス化する。- ボトムシート フローを作成する。
- ボタンフローを作成する。
- ログイン レスポンスを処理する。
- エラーを処理する。
- ログアウトを処理する。
アプリに依存関係を追加する
モジュールの build.gradle ファイルで、
認証情報マネージャー、Play 開発者サービス認証、
googleid の最新バージョンを使用して依存関係を宣言します。
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.6.0-rc02") implementation("androidx.credentials:credentials-play-services-auth:1.6.0-rc02") implementation("com.google.android.libraries.identity.googleid:googleid:<latest version>") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.6.0-rc02" implementation "androidx.credentials:credentials-play-services-auth:1.6.0-rc02" implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>" }
認証情報マネージャーをインスタンス化する
アプリまたはアクティビティのコンテキストを使用して、CredentialManager オブジェクトを作成します。
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
ボトムシート フローを作成する
ボトムシートは、認証情報マネージャーに組み込まれている UI です。この UI を使用すると、パスワード、パスキー、「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です。つまり、ボトムシート UI のデフォルトの動作では、以前に承認されたアカウントのみが表示されます。サーバー クライアント ID を設定する:
setServerClientIdパラメータを設定します。ThewebClientIdは、前提条件を満たす際に Google Cloud プロジェクトで OAuth 用に設定したウェブ クライアント ID です。自動ログインを有効にする(省略可): 再訪ユーザーの自動ログイン を有効にするには、
setAutoSelectEnabled(true)とsetFilterByAuthorizedAccounts(true)を使用します。アプリのユーザーが以前にログインしている場合、これにより不要な手間が省けます。自動ログインは、次の条件が満たされている場合にのみ可能です。
- デバイスに承認済みアカウントが 1 つしかなく、その承認済みアカウントが以前にデバイス上のアプリへのログインに使用されたことがある。デバイスに複数の承認済みアカウントがある場合、自動ログインは無効になります。
- ユーザーが前回のセッションでアプリから明示的にログアウトしていない。
- ユーザーが Google アカウント 設定で自動ログインを無効にしていない。
ノンスを設定する(省略可): セキュリティを強化するには、サーバーサイド認証用のノンスを設定します。リプレイ攻撃を防ぐため、
setNonce()を使用してサーバーサイド認証用のノンスを含めることができます。サーバーサイド コードで、リクエストとレスポンスのノンスが同一であることを検証してください。ノンスを生成するには、次の関数のような関数を使用します。この関数は、指定された長さの暗号学的に強力なランダム ノンスを生成し、
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()
coroutineScope {
try {
val result = credentialManager.getCredential(
request = request,
context = activityContext,
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failures
}
}
承認済みアカウントがない場合にログイン リクエストを構成する
デバイスにアプリの承認済みユーザーがいない場合、CredentialManager は NoCredentialException を返します。このシナリオでは、承認済みアカウント フィルタを無効にして、ユーザーが別のアカウントを使用して登録できるようにします。
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(WEB_CLIENT_ID)
.setNonce(generateSecureRandomNonce())
.build()
次に、ログインをリクエストします。承認済みアカウントの場合と同様です。
ボタンフローを作成する
次の条件でユーザーが「Google でログイン」できるようにする場合は、ボタンを使用します。
- ユーザーが認証情報マネージャーのボトムシート UI を閉じた。
- デバイスに Google アカウントがない。
- デバイス上の既存のアカウントの再認証が必要である。
ボタン UI を作成する
これは Jetpack Compose ボタンで実行できますが、 「Google でログイン」のブランド ガイドライン ページで事前承認されたブランド アイコンを使用することもできます。
ログインフローを作成する
GetSignInWithGoogleOption を使用して Google ログイン リクエストを作成し、Google ID トークンを取得します。
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(
serverClientId = WEB_CLIENT_ID
).setNonce(generateSecureRandomNonce())
.build()
次に、ログインをリクエストします。ボトムシート UI の場合と同様です。
ボトムシートとボタンの共有ログイン関数を作成する
ログインを処理するには、次の手順を行います。
- 認証情報マネージャーの
getCredential()関数を使用します。レスポンスが成功した場合は、CustomCredentialを抽出します。これはGoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL型である必要があります。 オブジェクトを
GoogleIdTokenCredentialに変換します。GoogleIdTokenCredential.createFrom()メソッドを使用します。GoogleIdTokenParsingException証明書利用者のサーバーで認証情報を検証します。
エラーを適切に処理していることを確認します。
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()
メソッドを呼び出して、すべての認証情報プロバイダから現在のユーザー認証情報の状態をクリアします。これにより、すべての認証情報プロバイダに、指定されたアプリの保存済み認証情報セッションをクリアするように通知され、次回はユーザーにすべてのログイン オプションが表示されます。