Credential Manager unterstützt Passkeys, die föderierte Anmeldung und Drittanbieter-Authentifizierungsanbieter und ist die empfohlene API für die Authentifizierung unter Android. Sie bietet eine sichere und praktische Umgebung, in der Nutzer ihre Anmeldedaten synchronisieren und verwalten können. Entwickler, die lokale FIDO2-Anmeldedaten verwenden, sollten ihre App aktualisieren, um die Passkey-Authentifizierung zu unterstützen. Dazu müssen sie die Credential Manager API einbinden. In diesem Dokument wird beschrieben, wie Sie Ihr Projekt von FIDO2 zu Credential Manager migrieren.
Gründe für die Migration von FIDO2 zu Credential Manager
In den meisten Fällen sollten Sie den Authentifizierungsanbieter Ihrer Android-App zu Credential Manager migrieren. Gründe für die Migration zu Credential Manager:
- Passkey-Unterstützung:Der Anmeldedaten-Manager unterstützt Passkeys, einen neuen, passwortlosen Authentifizierungsmechanismus, der sicherer und benutzerfreundlicher als Passwörter ist.
- Mehrere Anmeldemethoden:Der Anmeldedaten-Manager unterstützt mehrere Anmeldemethoden, darunter Passwörter, Passkeys und föderierte Anmeldemethoden. Dadurch wird es Nutzern einfacher, sich in Ihrer App zu authentifizieren, unabhängig von ihrer bevorzugten Authentifizierungsmethode.
- Unterstützung von Drittanbietern für Anmeldedaten: Unter Android 14 und höher unterstützt der Anmeldedaten-Manager mehrere Drittanbieter für Anmeldedaten. Das bedeutet, dass Nutzer sich mit ihren vorhandenen Anmeldedaten von anderen Anbietern in Ihrer App anmelden können.
- Einheitliche Nutzerfreundlichkeit:Credential Manager bietet eine einheitlichere Nutzerfreundlichkeit für die Authentifizierung in Apps und Anmeldemechanismen. So können Nutzer den Authentifizierungsablauf Ihrer App leichter nachvollziehen und verwenden.
Führen Sie die folgenden Schritte aus, um die Migration von FIDO2 zu Credential Manager zu starten.
Abhängigkeiten aktualisieren
Aktualisieren Sie das Kotlin-Plug-in in der Datei „build.gradle“ Ihres Projekts auf Version 1.8.10 oder höher.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
Aktualisieren Sie in der
build.gradle
Ihres Projekts Ihre Abhängigkeiten, um die neuesten Versionen der Credential Manager- und Play Services-Authentifizierungsbibliotheken zu verwenden.dependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
Ersetzen Sie die FIDO-Initialisierung durch die Credential Manager-Initialisierung. Fügen Sie diese Deklaration in die Klasse ein, die Sie für die Methoden zum Erstellen und Anmelden mit Passkeys verwenden:
val credMan = CredentialManager.create(context)
Passkeys erstellen
Sie müssen einen neuen Passkey erstellen, ihn mit dem Konto eines Nutzers verknüpfen und den öffentlichen Schlüssel des Passkeys auf Ihrem Server speichern, bevor sich der Nutzer damit anmelden kann. Richten Sie Ihre App für diese Funktion ein, indem Sie die Registrierungsfunktionsaufrufe aktualisieren.
Wenn Sie die erforderlichen Parameter abrufen möchten, die während der Passkey-Erstellung an die Methode
createCredential()
gesendet werden, fügen Sie IhremregisterRequest()
-Serveraufrufname("residentKey").value("required")
hinzu, wie in der WebAuthn-Spezifikation beschrieben.suspend fun registerRequest() { // ... val call = client.newCall( Builder() .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() ) // ... }
Legen Sie den Typ
return
fürregisterRequest()
und alle untergeordneten Funktionen aufJSONObject
fest.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } }).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }
Entfernen Sie alle Methoden, die Intent-Launcher- und Aktivitätsergebnisaufrufe verarbeiten, sicher aus Ihrer Ansicht.
Da
registerRequest()
jetzt eineJSONObject
zurückgibt, müssen Sie keinePendingIntent
erstellen. Ersetzen Sie den zurückgegebenen Intent durch einenJSONObject
. Aktualisieren Sie Ihre Intent-Launcher-Aufrufe, umcreateCredential()
aus der Credential Manager API aufzurufen. Rufen Sie die API-MethodecreateCredential()
auf.suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request = request as CreateCredentialRequest, context = activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
Wenn der Aufruf erfolgreich war, senden Sie die Antwort zurück an den Server. Anfrage und Antwort für diesen Aufruf ähneln der FIDO2-Implementierung, sodass keine Änderungen erforderlich sind.
Mit Passkeys authentifizieren
Nachdem Sie die Erstellung von Passkeys eingerichtet haben, können Sie Ihre App so konfigurieren, dass Nutzer sich mit ihren Passkeys anmelden und authentifizieren können. Dazu müssen Sie Ihren Authentifizierungscode aktualisieren, um Ergebnisse des Credential Manager zu verarbeiten, und eine Funktion zur Authentifizierung über Passkeys implementieren.
- Ihr Anmeldeanfrageaufruf an den Server, um die erforderlichen Informationen für die
getCredential()
-Anfrage abzurufen, ist derselbe wie bei der FIDO2-Implementierung. Es sind keine Änderungen erforderlich. Ähnlich wie beim Aufruf der Registrierungsanfrage wird die zurückgegebene Antwort im JSONObject-Format zurückgegeben.
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall(Builder().url(buildString { append("$BASE_URL/signinRequest") }).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie",formatCookie(sessionId)) .method("POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } }).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }
Entfernen Sie alle Methoden, die den Intent-Launcher und die Aktivitätsresult-Aufrufe verarbeiten, aus Ihrer Ansicht.
Da
signInRequest()
jetzt eineJSONObject
zurückgibt, müssen Sie keinePendingIntent
erstellen. Ersetzen Sie die zurückgegebene Absicht durchJSONObject
und rufen SiegetCredential()
aus Ihren API-Methoden auf.suspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT) .show() var result: GetCredentialResponse? = null try { val request= GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }
Senden Sie nach dem erfolgreichen Aufruf die Antwort zurück an den Server, um den Nutzer zu validieren und zu authentifizieren. Die Anfrage- und Antwortparameter für diesen API-Aufruf ähneln der FIDO2-Implementierung, sodass keine Änderungen erforderlich sind.
Zusätzliche Ressourcen
- Credential Manager-Beispielreferenz
- Credential Manager Codelab
- Nahtlose Authentifizierung in Apps mit Passkeys über die Credential Manager API
- FIDO2-Codelab