Con il supporto di passkey, accesso federato e provider di autenticazione di terze parti, Credential Manager è l'API consigliata per l'autenticazione su Android che fornisce un ambiente sicuro e pratico che consente agli utenti di sincronizzare e gestire le proprie credenziali. Per gli sviluppatori che utilizzano credenziali FIDO2 locali, è necessario aggiornare l'app per supportare l'autenticazione tramite passkey mediante l'integrazione con l'API Credential Manager. Questo documento descrive come eseguire la migrazione del progetto da FIDO2 a Gestore delle credenziali.
Motivi per eseguire la migrazione da FIDO2 a Gestore delle credenziali
Nella maggior parte dei casi, devi eseguire la migrazione del provider di autenticazione della tua app Android a Gestore delle credenziali. Ecco alcuni motivi per eseguire la migrazione a Gestore delle credenziali:
- Supporto delle passkey: Gestore delle credenziali supporta le passkey, un nuovo meccanismo di autenticazione senza password più sicuro e facile da usare rispetto alle password.
- Più metodi di accesso: Gestore delle credenziali supporta diversi metodi di accesso, inclusi password, passkey e metodi di accesso federato. In questo modo, gli utenti possono autenticarsi più facilmente nella tua app, indipendentemente dal metodo di autenticazione preferito.
- Assistenza per provider di credenziali di terze parti: su Android 14 e versioni successive, Gestore delle credenziali supporta più provider di credenziali di terze parti. Ciò significa che gli utenti possono utilizzare le credenziali esistenti di altri fornitori per accedere alla tua app.
- Esperienza utente coerente: Gestore delle credenziali fornisce un'esperienza utente più coerente per l'autenticazione in tutte le app e i meccanismi di accesso. In questo modo, gli utenti possono comprendere e utilizzare più facilmente il flusso di autenticazione della tua app.
Per iniziare la migrazione da FIDO2 a Gestore delle credenziali, segui i passaggi riportati di seguito.
Aggiorna le dipendenze
Aggiorna il plug-in Kotlin nel file build.gradle del progetto alla versione 1.8.10 o superiore.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
In build.gradle del progetto, aggiorna le dipendenze per utilizzare Gestore delle credenziali e l'autenticazione Play Services.
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>' // ... }
Sostituisci l'inizializzazione FIDO con l'inizializzazione di Gestore delle credenziali. Aggiungi questa dichiarazione alla classe che utilizzi per la creazione delle passkey e i metodi di accesso:
val credMan = CredentialManager.create(context)
Creare passkey
Prima che l'utente possa accedere con la passkey, dovrai creare una nuova passkey, associarla all'account di un utente e memorizzare la chiave pubblica della passkey sul tuo server. Configura la tua app con questa funzionalità aggiornando le chiamate alla funzione di registrazione.
Per ottenere i parametri necessari inviati al metodo
createCredential()
durante la creazione della passkey, aggiunginame("residentKey").value("required")
come descritto nella specifica WebAuthn) alla chiamata al serverregisterRequest()
.suspend fun registerRequest(sessionId: String ... { // ... .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() // ... }
Imposta il tipo
return
perregisterRequest()
e per tutte le funzioni secondarie suJSONObject
.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") ) } }
Rimuovi in sicurezza dalla visualizzazione tutti i metodi che gestiscono l'Avvio app di intent e le chiamate dei risultati dell'attività.
Poiché ora
registerRequest()
restituisce unJSONObject
, non è necessario creare unPendingIntent
. Sostituisci l'intent restituito con unJSONObject
. Aggiorna le chiamate all'avviatore di intent per chiamarecreateCredential()
dall'API Credential Manager. Chiama il metodo dell'APIcreateCredential()
.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 }
Una volta completata la chiamata, invia la risposta al server. La richiesta e la risposta per questa chiamata sono simili all'implementazione FIDO2, pertanto non sono necessarie modifiche.
Autenticazione con le passkey
Dopo aver configurato la creazione delle passkey, puoi configurare la tua app in modo da consentire agli utenti di accedere e autenticarsi utilizzando le loro passkey. Per farlo, aggiornerai il codice di autenticazione per gestire i risultati di Gestore delle credenziali e implementerai una funzione per l'autenticazione tramite passkey.
- La chiamata alla richiesta di accesso al server per ottenere le informazioni necessarie da inviare alla richiesta
getCredential()
corrisponde all'implementazione FIDO2. Non sono necessarie modifiche. Come per la chiamata della richiesta di registrazione, la risposta restituita è in formato JSONObject.
/** * @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") { } }
Rimuovi in sicurezza dalla visualizzazione tutti i metodi che gestiscono le chiamate all'avviatore di intent e al risultato dell'attività.
Poiché
signInRequest()
ora restituisce unJSONObject
, non è necessario creare unPendingIntent
. Sostituisci l'intent restituito con unJSONObject
e chiamagetCredential()
dai tuoi metodi API.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 }
Una volta completata la chiamata, invia la risposta al server per verificare e autenticare l'utente. I parametri di richiesta e risposta per questa chiamata API sono simili all'implementazione FIDO2, pertanto non sono necessarie modifiche.
Risorse aggiuntive
- Riferimento di esempio di Gestore delle credenziali
- Codelab sul Gestore delle credenziali
- Offrire un'autenticazione senza problemi alle tue app con le passkey utilizzando l'API Credential Manager
- Codelab FIDO2