Mit Unterstützung für Passkeys, die föderierte Anmeldung und Authentifizierungsanbieter von Drittanbietern ist Credential Manager 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. Wenn Entwickler lokale FIDO2-Anmeldedaten verwenden, sollten Sie Ihre App so aktualisieren, dass sie die Passkey-Authentifizierung unterstützt. Dazu integrieren Sie sie in die Credential Manager API. In diesem Dokument wird beschrieben, wie Sie Ihr Projekt von FIDO2 zu Credential Manager migrieren können.
Gründe für die Migration von FIDO2 zum Anmeldedaten-Manager
In den meisten Fällen sollten Sie den Authentifizierungsanbieter Ihrer Android-App zu Credential Manager migrieren. Gründe für die Migration zum Anmeldedaten-Manager:
- Unterstützung von Passkeys:Der Anmeldedaten-Manager unterstützt Passkeys, einen neuen, passwortlosen Authentifizierungsmechanismus, der sicherer und einfacher zu verwenden ist als Passwörter.
- Mehrfachanmeldung:Die Anmeldedaten-Manager unterstützt Mehrfachanmeldungsmethoden, darunter Passwörter, Passkeys und Verbundanmeldungsmethoden. So können sich Nutzer unabhängig von ihrer bevorzugten Authentifizierungsmethode einfacher in Ihrer App authentifizieren.
- Unterstützung von Anmeldedatenanbietern von Drittanbietern:Unter Android 14 und höher unterstützt der Anmeldedaten-Manager mehrere Anmeldedatenanbieter von Drittanbietern. Das bedeutet, dass Ihre Nutzer ihre vorhandenen Anmeldedaten von anderen Anbietern verwenden können, um sich bei Ihrer Anwendung anzumelden.
- Einheitliche Nutzung:Der Credential Manager bietet eine konsistentere Nutzerumgebung für die Authentifizierung über Apps und Anmeldemechanismen hinweg. Dies erleichtert Nutzern das Verständnis und die Verwendung des Authentifizierungsvorgangs Ihrer Anwendung.
Führen Sie die folgenden Schritte aus, um mit der Migration von FIDO2 zum Anmeldedaten-Manager zu beginnen.
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 Datei „build.gradle“ Ihres Projekts die Abhängigkeiten, damit der Anmeldedaten-Manager und die Play-Dienste-Authentifizierung verwendet werden.
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 Initialisierung des Anmeldedaten-Managers. Fügen Sie diese Deklaration in die Klasse ein, die Sie für die Erstellung von Passkeys und Anmeldemethoden 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. Aktivieren Sie diese Funktion in Ihrer App, indem Sie die Funktionsaufrufe für die Registrierung aktualisieren.
Wenn du die erforderlichen Parameter abrufen möchtest, die beim Erstellen eines Passkeys an die Methode
createCredential()
gesendet werden, füge deinemregisterRequest()
-Serveraufrufname("residentKey").value("required")
wie in der WebAuthn-Spezifikation beschrieben hinzu.suspend fun registerRequest(sessionId: String ... { // ... .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( Request.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ätsergebnisse verarbeiten, sicher aus Ihrer Ansicht.
Da
registerRequest()
jetzt eineJSONObject
zurückgibt, müssen Sie keinePendingIntent
erstellen. Ersetzen Sie den zurückgegebenen Intent durch eineJSONObject
. Aktualisieren Sie Ihre Intent-Launcher-Aufrufe, umcreateCredential()
über die 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 as CreateCredentialRequest, activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
Sende die Antwort nach erfolgreichem Aufruf an den Server zurück. Die Anfrage und Antwort für diesen Aufruf ähneln der FIDO2-Implementierung, sodass keine Änderungen erforderlich sind.
Mit Passkeys authentifizieren
Nachdem du die Erstellung von Passkeys eingerichtet hast, kannst du deine App so einrichten, dass sich Nutzer mit ihren Passkeys anmelden und authentifizieren können. Dazu aktualisieren Sie Ihren Authentifizierungscode, um die Ergebnisse des Anmeldedaten-Managers zu verarbeiten, und implementieren eine Funktion zur Authentifizierung über Passkeys.
- Der Aufruf der Anmeldeanfrage an den Server, um die erforderlichen Informationen für die
getCredential()
-Anfrage abzurufen, entspricht der FIDO2-Implementierung. Es sind keine Änderungen erforderlich. Ähnlich wie beim Aufruf der Registrierungsanfrage wird die 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 sicher alle Methoden, die den Intent-Launcher und die Aufrufe von Aktivitätsergebnissen verarbeiten, aus Ihrer Ansicht.
Da
signInRequest()
jetzt eineJSONObject
zurückgibt, müssen Sie keinePendingIntent
erstellen. Ersetzen Sie die zurückgegebene Absicht durch einenJSONObject
und rufen SiegetCredential()
über Ihre 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 }
Wenn der Aufruf erfolgreich war, senden Sie die Antwort an den Server zurück, um den Nutzer zu überprüfen und zu authentifizieren. Die Anfrage- und Antwortparameter für diesen API-Aufruf ähneln der FIDO2-Implementierung. Daher sind keine Änderungen erforderlich.
Weitere Informationen
- Beispielreferenz für Credential Manager
- Codelab zum Credential Manager
- Seamless Authentication für Ihre Apps mit Passkeys über die Credential Manager API
- FIDO2-Codelab