Revisione 2025 T4: scopri come semplificare i percorsi di autenticazione utilizzando l'API Credential Manager nella tua app per Android

1. Prima di iniziare

Le soluzioni di autenticazione tradizionali presentano una serie di sfide in termini di sicurezza e usabilità.

Le password sono ampiamente utilizzate, ma…

  • Facili da dimenticare
  • Gli utenti devono avere le conoscenze necessarie per creare password efficaci.
  • Facili da usare per il phishing, la raccolta e la riproduzione da parte degli autori degli attacchi.

Android ha lavorato alla creazione dell'API Credential Manager per semplificare l'esperienza di accesso e affrontare i rischi per la sicurezza supportando le passkey, lo standard di settore di nuova generazione per l'autenticazione senza password.

Gestore delle credenziali riunisce il supporto per le passkey e lo combina con i metodi di autenticazione tradizionali, come password, Accedi con Google e così via.

Gli utenti potranno creare passkey, memorizzarle in Gestore delle password di Google, che le sincronizzerà sui dispositivi Android su cui l'utente ha eseguito l'accesso. Prima che un utente possa accedere con una passkey, questa deve essere creata, associata a un account utente e la relativa chiave pubblica deve essere memorizzata su un server.

In questo codelab, imparerai a registrarti utilizzando passkey e password tramite l'API Credential Manager e a utilizzarle per scopi di autenticazione futuri. Esistono due flussi, tra cui:

  • Registrazione : utilizzando passkey e password.
  • Accedi : utilizzando le passkey e la password salvata.

Prerequisiti

  • Conoscenza di base di come eseguire le app in Android Studio.
  • Conoscenza di base del flusso di autenticazione nelle app per Android.
  • Conoscenza di base delle passkey.

Obiettivi didattici

  • Come creare una passkey.
  • Come salvare la password nel gestore delle password.
  • Come autenticare gli utenti con una passkey o una password salvata.

Che cosa ti serve

Una delle seguenti combinazioni di dispositivi:

  • Un dispositivo Android con Android 9 o versioni successive (per le passkey) e Android 4.4 o versioni successive(per l'autenticazione con password tramite l'API Credential Manager).
  • Dispositivo preferibilmente con un sensore biometrico.
  • Assicurati di registrare un blocco schermo (biometrico o di altro tipo).
  • Versione del plug-in Kotlin : 1.8.10

2. Configurazione

Questa app di esempio richiede un collegamento delle risorse digitali a un sito web affinché Gestore delle credenziali possa convalidare il collegamento e procedere ulteriormente, quindi l'ID rp utilizzato nelle risposte simulate proviene da un server di terze parti simulato. Se vuoi provare la tua risposta simulata, aggiungi il dominio dell'app e non dimenticare di completare il collegamento delle risorse digitali come indicato qui.

Utilizza lo stesso debug.keystore menzionato nel progetto per creare varianti di debug e release per verificare il collegamento delle risorse digitali del nome pacchetto e di SHA sul server di simulazione. (Questo passaggio è già stato eseguito per te per l'app di esempio in build.gradle).

  1. Clona questo repository sul tuo laptop dal ramo credman_codelab: https://github.com/android/identity-samples/tree/credman_codelab
git clone -b credman_codelab https://github.com/android/identity-samples.git
  1. Vai al modulo CredentialManager e apri il progetto in Android Studio.

Vediamo lo stato iniziale dell'app

Per vedere come funziona lo stato iniziale dell'app, segui questi passaggi:

  1. Avvia l'app.
  2. Viene visualizzata una schermata principale con un pulsante di registrazione e accesso. Questi pulsanti non fanno ancora nulla, ma ne abiliteremo la funzionalità nelle sezioni successive.

7a6fe80f4cf877a8.jpeg

3. Aggiungere la possibilità di registrarsi utilizzando le passkey

Quando si registra un nuovo account su un'app per Android che utilizza l'API Credential Manager, l'utente può creare una passkey per il proprio account. Questa passkey verrà archiviata in modo sicuro nel provider di credenziali scelto dall'utente e utilizzata per gli accessi futuri, senza richiedere all'utente di inserire la password ogni volta.

Ora creerai una passkey e registrerai le credenziali utente utilizzando la biometria/il blocco schermo.

Registrarsi con la passkey

Il codice all'interno di CredentialManager/app/src/main/java/com/google/credentialmanager/sample/SignUpScreen.kt definisce un campo di testo "username" e un pulsante per registrarsi con una passkey.

1f4c50daa2551f1.jpeg

Definisci la lambda createCredential() da utilizzare nei modelli di visualizzazione

Gli oggetti Gestore delle credenziali richiedono il passaggio di un Activity, associato a una schermata. Tuttavia, le operazioni di Credential Manager vengono in genere attivate in Visualizza modelli e non è consigliabile fare riferimento alle attività all'interno di Visualizza modelli. Pertanto, definiamo le funzioni di Credential Manager in un file separato CredentialManagerUtil.kt e le facciamo riferimento nelle schermate appropriate, che poi le passano ai relativi View Model come callback tramite funzioni lambda.

Individua il commento TODO nella funzione createCredential() in CredentialManagerUtil.kt e chiama la funzione CredentialManager.create():

CredentialManagerUtil.kt

suspend fun createCredential(
    activity: Activity,
    request: CreateCredentialRequest
): CreateCredentialResponse {
    TODO("Create a CredentialManager object and call createCredential() with a CreateCredentialRequest")
    val credentialManager = CredentialManager.create(activity)
    return credentialManager.createCredential(activity, request)
}

Passa la sfida e l'altra risposta JSON a una chiamata createPasskey()

Prima di creare una passkey, devi richiedere al server le informazioni necessarie da trasmettere all'API Credential Manager durante la chiamata createCredential().

Hai già una risposta simulata negli asset del progetto, denominata RegFromServer.txt, che restituisce i parametri necessari in questo codelab.

  • Nella tua app, vai a SignUpViewModel.kt. Trova il metodo signUpWithPasskeys in cui scriverai la logica per creare una passkey e consentire l'accesso all'utente. Puoi trovare il metodo nella stessa classe.
  • Individua il blocco di commenti TODO in create a CreatePublicKeyCredentialRequest() e sostituiscilo con il seguente codice:

SignUpViewModel.kt

TODO("Create a CreatePublicKeyCredentialRequest() with necessary registration json from server")
    val request = CreatePublicKeyCredentialRequest(
        jsonProvider.fetchRegistrationJson()
            .replace("<userId>", getEncodedUserId())
            .replace("<userName>", _username.value)
            .replace("<userDisplayName>", _username.value)
            .replace("<challenge>", getEncodedChallenge())
    )

Il metodo jsonProvider.fetchRegistrationJsonFromServer() legge una risposta JSON PublicKeyCredentialCreationOptions del server emulato dagli asset e restituisce il JSON di registrazione da passare durante la creazione della passkey. Sostituiamo alcuni valori dei segnaposto con le voci degli utenti della nostra app e alcuni campi simulati:

  • Questo JSON è incompleto e contiene 4 campi che devono essere sostituiti.
  • L'ID utente deve essere univoco in modo che un utente possa creare più passkey (se necessario). Sostituisci <userId> con il valore userId generato.
  • Anche <challenge> deve essere univoco, quindi genererai una sfida univoca casuale. Il metodo è già presente nel tuo codice.

Una risposta del server reale PublicKeyCredentialCreationOptions potrebbe restituire più opzioni. Di seguito è riportato un esempio di alcuni di questi campi:

{
  "challenge": String,
  "rp": {
    "name": String,
    "id": String
  },
  "user": {
    "id": String,
    "name": String,
    "displayName": String
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

La tabella seguente spiega alcuni dei parametri importanti di un oggetto PublicKeyCredentialCreationOptions:

Parametri

Descrizioni

challenge

Una stringa casuale generata dal server che contiene entropia sufficiente per renderne impossibile l'ipotesi. Deve avere una lunghezza di almeno 16 byte. Questo campo è obbligatorio, ma non viene utilizzato durante la registrazione, a meno che non venga eseguita l'attestazione.

user.id

L'ID univoco di un utente. Questo valore non deve includere informazioni che consentono l'identificazione personale, ad esempio indirizzi email o nomi utente. Un valore casuale di 16 byte generato per account funzionerà bene.

user.name

Questo campo deve contenere un identificatore univoco per l'account che l'utente riconoscerà, ad esempio il suo indirizzo email o nome utente. Verrà visualizzato nel selettore account. Se utilizzi un nome utente, utilizza lo stesso valore dell'autenticazione con password.

user.displayName

Questo campo è un nome facoltativo e più intuitivo per l'account.

rp.id

L'entità Relying Party corrisponde ai dettagli della tua applicazione. Ha i seguenti attributi:

  • name (obbligatorio): il nome dell'applicazione
  • (Facoltativo) ID: corrisponde al dominio o al sottodominio. Se assente, viene utilizzato il dominio corrente.
  • icon (facoltativo).

pubKeyCredParams

Elenco di algoritmi e tipi di chiavi consentiti. Questo elenco deve contenere almeno un elemento.

excludeCredentials

L'utente che tenta di registrare un dispositivo potrebbe aver registrato altri dispositivi. Per limitare la creazione di più credenziali per lo stesso account su un singolo autenticatore, puoi ignorare questi dispositivi. Il membro transports, se fornito, deve contenere il risultato della chiamata a getTransports() durante la registrazione di ogni credenziale.

authenticatorSelection.authenticatorAttachment

Indica se il dispositivo deve essere collegato alla piattaforma o meno o se non è necessario farlo. Imposta questo valore su platform. Ciò indica che vuoi un autenticatore incorporato nel dispositivo della piattaforma e all'utente non verrà chiesto di inserire, ad esempio, un token di sicurezza USB.

residentKey

indica il valore required per creare una passkey.

Crea una qualifica

  1. Una volta creato un CreatePublicKeyCredentialRequest(), devi chiamare la chiamata createCredential() con la richiesta creata.

SignUpViewModel.kt

try {
   TODO("Call createCredential() with createPublicKeyCredentialRequest")
   createCredential(request)
   TODO("Complete the registration process after sending public key credential to your server and let the user in")

} catch (e: CreateCredentialException) {
   handlePasskeyFailure(e)
}

  • Gestisci la visibilità delle visualizzazioni sottoposte a rendering e gestisci le eccezioni se la richiesta non va a buon fine o non riesce per qualche motivo. Qui i messaggi di errore vengono registrati e mostrati nell'app in una finestra di dialogo di errore. Puoi controllare i log degli errori completi tramite Android Studio o il comando adb debug.

1ea8ace66135de1e.png

  1. Infine, devi completare la procedura di registrazione. L'app invia una credenziale di chiave pubblica al server, che la registra per l'utente corrente.

Qui abbiamo utilizzato un server di test, quindi restituiamo semplicemente il valore true per indicare che il server ha salvato la chiave pubblica registrata per scopi di autenticazione e convalida futuri. Per la tua implementazione, puoi scoprire di più sulla registrazione delle passkey lato server.

All'interno del metodo signUpWithPasskeys(), trova il commento pertinente e sostituiscilo con il seguente codice:

SignUpViewModel.kt

try {
    createCredential(request)
    TODO("Complete the registration process after sending public key credential to your server and let the user in")
registerResponse()
    DataProvider.setSignedInThroughPasskeys(true)
    _navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = true))
} catch (e: CreateCredentialException) {
   handlePasskeyFailure(e)
}
  • registerResponse() restituisce true, a indicare che il server di test ha salvato la chiave pubblica per un uso futuro.
  • Imposta il flag setSignedInThroughPasskeys su true.
  • Una volta eseguito l'accesso, reindirizza l'utente alla schermata Home.

Un PublicKeyCredential reale può contenere più campi. Di seguito è riportato un esempio di questi campi:

{
  "id": String,
  "rawId": String,
  "type": "public-key",
  "response": {
    "clientDataJSON": String,
    "attestationObject": String,
  }
}

La tabella seguente spiega alcuni dei parametri importanti di un oggetto PublicKeyCredential:

Parametri

Descrizioni

id

Un ID con codifica Base64URL della passkey creata. Questo ID aiuta il browser a determinare se è presente una passkey corrispondente nel dispositivo durante l'autenticazione. Questo valore deve essere memorizzato nel database sul backend.

rawId

Una versione dell'ID credenziali dell'oggetto ArrayBuffer.

response.clientDataJSON

Un oggetto ArrayBuffer codifica i dati del cliente.

response.attestationObject

Un oggetto di attestazione codificato ArrayBuffer. Contiene informazioni importanti, come un ID RP, flag e una chiave pubblica.

Esegui l'app e potrai fare clic sul pulsante Registrati con le passkey e creare una passkey.

4. Salvare una password nel provider di credenziali

In questa app, all'interno della schermata di registrazione, è già stata implementata una registrazione con nome utente e password a scopo dimostrativo.

Per salvare la credenziale della password utente con il relativo fornitore di password, implementa un CreatePasswordRequest da passare a createCredential() per salvare la password.

  • Trova il metodo signUpWithPassword(), sostituisci TODO con una chiamata createPassword:

SignUpViewModel.kt

TODO("CreatePasswordRequest with entered username and password")