Gestore delle credenziali è un'API Jetpack che supporta più metodi di accesso, come nome utente e password, passkey e soluzioni di accesso federato (come Accedi con Google), in un'unica API, semplificando così l'integrazione per gli sviluppatori.
Inoltre, per gli utenti, Credential Manager unifica l'interfaccia di accesso tra i metodi di autenticazione, rendendo più chiaro e facile per gli utenti accedere alle app, indipendentemente dal metodo scelto.
Questa pagina spiega il concetto di passkey e i passaggi per implementare il supporto lato client per le soluzioni di autenticazione, incluse le passkey, utilizzando l'API Credential Manager. Esiste anche una pagina delle domande frequenti separata che fornisce risposte a domande più dettagliate e specifiche.
Il tuo feedback è fondamentale per migliorare l'API Credential Manager. Condividi eventuali problemi rilevati o idee per migliorare l'API utilizzando il seguente link:
Informazioni sulle passkey
Le passkey sono un'alternativa più sicura e semplice alle password. Con le passkey, gli utenti possono accedere ad app e siti web utilizzando un sensore biometrico (ad esempio un sistema di riconoscimento delle impronte o del volto), un PIN o una sequenza. Ciò fornisce un'esperienza di accesso, in modo che gli utenti non debbano ricordare nomi utente password.
Le passkey si basano su WebAuthn (Web Authentication), uno standard sviluppato congiuntamente la FIDO Alliance e il World Wide Web Consortium (W3C). WebAuthn utilizza la crittografia con chiave pubblica per autenticare l'utente. Il sito web o l'app a cui l'utente accede può vedere e memorizzare la chiave pubblica, ma mai la chiave privata. La chiave privata viene mantenuta segreta e al sicuro. Poiché la chiave è univoca legate al sito web o all'app, le passkey non sono soggette a phishing, il che aggiunge ulteriore sicurezza.
Gestore delle credenziali consente agli utenti di creare passkey e memorizzarle in Google Gestore delle password.
Leggi l'articolo Autenticazione utente con passkey per indicazioni su come implementare flussi di autenticazione con passkey senza interruzioni con Gestore delle credenziali.
Prerequisiti
Per utilizzare Gestore delle credenziali, completa i passaggi descritti in questa sezione.
Utilizza una versione recente della piattaforma
Gestore delle credenziali è supportato su Android 4.4 (livello API 19) e versioni successive.
Aggiungi dipendenze all'app
Aggiungi le seguenti dipendenze allo script di build del tuo modulo dell'app:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.5.0-alpha05") // optional - needed for credentials support from play services, for devices running // Android 13 and below. implementation("androidx.credentials:credentials-play-services-auth:1.5.0-alpha05") }
Alla moda
dependencies { implementation "androidx.credentials:credentials:1.5.0-alpha05" // optional - needed for credentials support from play services, for devices running // Android 13 and below. implementation "androidx.credentials:credentials-play-services-auth:1.5.0-alpha05" }
Mantieni le classi nel file ProGuard
Nel file proguard-rules.pro
del modulo, aggiungi le seguenti direttive:
-if class androidx.credentials.CredentialManager
-keep class androidx.credentials.playservices.** {
*;
}
Scopri di più su come ridurre le dimensioni, offuscare e ottimizzare l'app.
Aggiungere il supporto per Digital Asset Links
Per attivare il supporto delle passkey per la tua app per Android, associala a un sito web di tua proprietà. Per dichiarare questa associazione, segui i seguenti passaggi:
Crea un file JSON Digital Asset Links. Ad esempio, per dichiarare che sito web
https://signin.example.com
e un'app per Android con il pacchetto nomecom.example
può condividere le credenziali di accesso, creare un file denominatoassetlinks.json
con i seguenti contenuti:[ { "relation" : [ "delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds" ], "target" : { "namespace" : "android_app", "package_name" : "com.example.android", "sha256_cert_fingerprints" : [ SHA_HEX_VALUE ] } } ]
Il campo
relation
è un array di una o più stringhe che descrivono il della relazione che viene dichiarata. Per dichiarare che le app e i siti condividono le credenziali di accesso, specifica le relazioni comedelegate_permission/handle_all_urls
edelegate_permission/common.get_login_creds
.Il campo
target
è un oggetto che specifica la risorsa a cui si applica la dichiarazione. I seguenti campi identificano un sito web:namespace
web
site
L'URL del sito web nel formato
https://domain[:optional_port]
; ad esempio,https://www.example.com
.domain deve essere pienamente idonea. e Se si utilizza la porta 443 per, è necessario omettere optional_port HTTPS.
Un target
site
può essere solo un dominio principale: non puoi Limita l'associazione di un'app a una sottodirectory specifica. Non includere un percorso dell'URL, ad esempio una barra finale.I sottodomini non sono considerati corrispondenze: in altre parole, se specifichi domain come
www.example.com
, il dominiowww.counter.example.com
non è associato alla tua app.I seguenti campi identificano un'app per Android:
namespace
android_app
package_name
Il nome del pacchetto dichiarato nel file manifest dell'app. Ad esempio: com.example.android
sha256_cert_fingerprints
Le impronte SHA256 dei modelli di machine learning di firmare il certificato. Ospita il file JSON Digital Resources Link nella seguente posizione sulla dominio di accesso:
https://domain[:optional_port]/.well-known/assetlinks.json
Ad esempio, se il tuo dominio di accesso è
signin.example.com
, ospita il file JSON all'indirizzohttps://signin.example.com/.well-known/assetlinks.json
.Il tipo MIME per il file Digital Asset Link deve essere JSON. Assicurati che il server invii un'intestazione
Content-Type: application/json
nella risposta.Assicurati che il tuo host consenta a Google di recuperare il file Digital Asset Link. Se hai un file
robots.txt
, questo deve consentire all'agente Googlebot di recupera/.well-known/assetlinks.json
. La maggior parte dei siti consente qualsiasi agente automatico di recuperare i file nel percorso/.well-known/
in modo che possono accedere ai metadati contenuti nei file:User-agent: * Allow: /.well-known/
Aggiungi la seguente riga al file manifest in
<application>
:<meta-data android:name="asset_statements" android:resource="@string/asset_statements" />
Se utilizzi l'accesso con password tramite Gestore delle credenziali, segui questo passaggio per configurare il collegamento delle risorse digitali nel file manifest. Questo passaggio non è obbligatorio se utilizzi solo le passkey.
Dichiara l'associazione nell'app per Android. Aggiungi un oggetto che specifichi i file
assetlinks.json
da caricare. Devi eseguire l'interpretazione letterale di eventuali apostrofi e virgolette utilizzati nella stringa. Ad esempio:<string name="asset_statements" translatable="false"> [{ \"include\": \"https://signin.example.com/.well-known/assetlinks.json\" }] </string>
> GET /.well-known/assetlinks.json HTTP/1.1 > User-Agent: curl/7.35.0 > Host: signin.example.com < HTTP/1.1 200 OK < Content-Type: application/json
Configura Gestore delle credenziali
Per configurare e inizializzare un oggetto CredentialManager
, aggiungi una logica simile a
le seguenti:
Kotlin
// Use your app or activity context to instantiate a client instance of // CredentialManager. val credentialManager = CredentialManager.create(context)
Java
// Use your app or activity context to instantiate a client instance of // CredentialManager. CredentialManager credentialManager = CredentialManager.create(context)
Indica i campi delle credenziali
Su Android 14 e versioni successive, l'attributo isCredential
può essere utilizzato per indicare i campi delle credenziali, ad esempio i campi nome utente o password. Questo attributo
indica che questa vista è un campo delle credenziali che deve essere utilizzato
Gestore delle credenziali e provider di credenziali di terze parti, facilitando al contempo la compilazione automatica
offrono suggerimenti migliori
di compilazione automatica. Quando l'app utilizza la credenziale
API Manager, il riquadro inferiore di Gestore delle credenziali con le credenziali disponibili
e non è necessario mostrare la finestra di dialogo di compilazione automatica per
nome utente o password. Analogamente, non è necessario mostrare
salva la finestra di dialogo per le password, poiché l'app richiederà l'API Credential Manager
per salvare le credenziali.
Per utilizzare l'attributo isCredential
, aggiungilo alle visualizzazioni pertinenti:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true"
...
/>
Accedi all'utente
Per recuperare tutte le opzioni di passkey e password associate all'account dell'utente:
Inizializza le opzioni di autenticazione con password e passkey:
Kotlin
// Retrieves the user's saved password for your app from their // password provider. val getPasswordOption = GetPasswordOption() // Get passkey from the user's public key credential provider. val getPublicKeyCredentialOption = GetPublicKeyCredentialOption( requestJson = requestJson )
Java
// Retrieves the user's saved password for your app from their // password provider. GetPasswordOption getPasswordOption = new GetPasswordOption(); // Get passkey from the user's public key credential provider. GetPublicKeyCredentialOption getPublicKeyCredentialOption = new GetPublicKeyCredentialOption(requestJson);
Utilizza le opzioni recuperate dal passaggio precedente per creare richiesta di accesso.
Kotlin
val getCredRequest = GetCredentialRequest( listOf(getPasswordOption, getPublicKeyCredentialOption) )
Java
GetCredentialRequest getCredRequest = new GetCredentialRequest.Builder() .addCredentialOption(getPasswordOption) .addCredentialOption(getPublicKeyCredentialOption) .build();
Avvia il flusso di accesso:
Kotlin
coroutineScope.launch { try { val result = credentialManager.getCredential( // Use an activity-based context to avoid undefined system UI // launching behavior. context = activityContext, request = getCredRequest ) handleSignIn(result) } catch (e : GetCredentialException) { handleFailure(e) } } fun handleSignIn(result: GetCredentialResponse) { // Handle the successfully returned credential. val credential = result.credential when (credential) { is PublicKeyCredential -> { val responseJson = credential.authenticationResponseJson // Share responseJson i.e. a GetCredentialResponse on your server to // validate and authenticate } is PasswordCredential -> { val username = credential.id val password = credential.password // Use id and password to send to your server to validate // and authenticate } is CustomCredential -> { // If you are also using any external sign-in libraries, parse them // here with the utility functions provided. if (credential.type == ExampleCustomCredential.TYPE) { try { val ExampleCustomCredential = ExampleCustomCredential.createFrom(credential.data) // Extract the required credentials and complete the authentication as per // the federated sign in or any external sign in library flow } catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) { // Unlikely to happen. If it does, you likely need to update the dependency // version of your external sign-in library. Log.e(TAG, "Failed to parse an ExampleCustomCredential", e) } } else { // Catch any unrecognized custom credential type here. Log.e(TAG, "Unexpected type of credential") } } else -> { // Catch any unrecognized credential type here. Log.e(TAG, "Unexpected type of credential") } } }
Java
credentialManager.getCredentialAsync( // Use activity based context to avoid undefined // system UI launching behavior activity, getCredRequest, cancellationSignal, <executor>, new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() { @Override public void onResult(GetCredentialResponse result) { handleSignIn(result); } @Override public void onError(GetCredentialException e) { handleFailure(e); } } ); public void handleSignIn(GetCredentialResponse result) { // Handle the successfully returned credential. Credential credential = result.getCredential(); if (credential instanceof PublicKeyCredential) { String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson(); // Share responseJson i.e. a GetCredentialResponse on your server to validate and authenticate } else if (credential instanceof PasswordCredential) { String username = ((PasswordCredential) credential).getId(); String password = ((PasswordCredential) credential).getPassword(); // Use id and password to send to your server to validate and authenticate } else if (credential instanceof CustomCredential) { if (ExampleCustomCredential.TYPE.equals(credential.getType())) { try { ExampleCustomCredential customCred = ExampleCustomCredential.createFrom(customCredential.getData()); // Extract the required credentials and complete the // authentication as per the federated sign in or any external // sign in library flow } catch (ExampleCustomCredential.ExampleCustomCredentialParsingException e) { // Unlikely to happen. If it does, you likely need to update the // dependency version of your external sign-in library. Log.e(TAG, "Failed to parse an ExampleCustomCredential", e); } } else { // Catch any unrecognized custom credential type here. Log.e(TAG, "Unexpected type of credential"); } } else { // Catch any unrecognized credential type here. Log.e(TAG, "Unexpected type of credential"); } }
L'esempio seguente mostra come formattare la richiesta JSON quando ricevi una passkey:
{
"challenge": "T1xCsnxM2DNL2KdK5CLa6fMhD7OBqho6syzInk_n-Uo",
"allowCredentials": [],
"timeout": 1800000,
"userVerification": "required",
"rpId": "credential-manager-app-test.glitch.me"
}
L'esempio seguente mostra l'aspetto di una risposta JSON dopo che hai ricevuto un credenziale chiave pubblica:
{
"id": "KEDetxZcUfinhVi6Za5nZQ",
"type": "public-key",
"rawId": "KEDetxZcUfinhVi6Za5nZQ",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVDF4Q3NueE0yRE5MMktkSzVDTGE2Zk1oRDdPQnFobzZzeXpJbmtfbi1VbyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
"authenticatorData": "j5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGQdAAAAAA",
"signature": "MEUCIQCO1Cm4SA2xiG5FdKDHCJorueiS04wCsqHhiRDbbgITYAIgMKMFirgC2SSFmxrh7z9PzUqr0bK1HZ6Zn8vZVhETnyQ",
"userHandle": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0"
}
}
Gestire le eccezioni quando non sono disponibili credenziali
In alcuni casi, l'utente potrebbe non avere alcuna credenziale disponibile oppure l'utente potrebbe
non concedere il consenso all'utilizzo di una credenziale disponibile. Se viene invocato getCredential()
e non vengono trovate credenziali, viene restituito un NoCredentialException
. In questo caso, il codice deve gestire le istanze NoCredentialException
.
Kotlin
try {
val credential = credentialManager.getCredential(credentialRequest)
} catch (e: NoCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
Java
try {
Credential credential = credentialManager.getCredential(credentialRequest);
} catch (NoCredentialException e) {
Log.e("CredentialManager", "No credential available", e);
}
Su Android 14 o versioni successive, puoi ridurre la latenza quando mostri il selettore di account utilizzando il metodo prepareGetCredential()
prima di chiamare getCredential()
.
Kotlin
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
<getPublicKeyCredentialOption>,
<getPasswordOption>
)
)
}
Java
GetCredentialResponse response = credentialManager.prepareGetCredential(
new GetCredentialRequest(
Arrays.asList(
new PublicKeyCredentialOption(),
new PasswordOption()
)
)
);
Il metodo prepareGetCredential()
non richiama elementi UI. Ti aiuta solo a eseguire i preparativi in modo da poter avviare in un secondo momento l'operazione di recupero delle credenziali rimanente (che coinvolge le UI) tramite l'API getCredential()
.
I dati memorizzati nella cache vengono restituiti in un oggetto PrepareGetCredentialResponse
. Se esistono credenziali, i risultati verranno memorizzati nella cache e in un secondo momento potrai avviare l'API getCredential()
rimanente per visualizzare il selettore dell'account con i dati memorizzati nella cache.
Flussi di registrazione
Puoi registrare un utente per l'autenticazione utilizzando una passkey o una password.
Crea una passkey
Per offrire agli utenti la possibilità di registrare una passkey e utilizzarla per la ri-autenticazione,
registra una credenziale utente utilizzando un oggetto CreatePublicKeyCredentialRequest
.
Kotlin
fun createPasskey(requestJson: String, preferImmediatelyAvailableCredentials: Boolean) { val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest( // Contains the request in JSON format. Uses the standard WebAuthn // web JSON spec. requestJson = requestJson, // Defines whether you prefer to use only immediately available // credentials, not hybrid credentials, to fulfill this request. // This value is false by default. preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials, ) // Execute CreateCredentialRequest asynchronously to register credentials // for a user account. Handle success and failure cases with the result and // exceptions, respectively. coroutineScope.launch { try { val result = credentialManager.createCredential( // Use an activity-based context to avoid undefined system // UI launching behavior context = activityContext, request = createPublicKeyCredentialRequest, ) handlePasskeyRegistrationResult(result) } catch (e : CreateCredentialException){ handleFailure(e) } } } fun handleFailure(e: CreateCredentialException) { when (e) { is CreatePublicKeyCredentialDomException -> { // Handle the passkey DOM errors thrown according to the // WebAuthn spec. handlePasskeyError(e.domError) } is CreateCredentialCancellationException -> { // The user intentionally canceled the operation and chose not // to register the credential. } is CreateCredentialInterruptedException -> { // Retry-able error. Consider retrying the call. } is CreateCredentialProviderConfigurationException -> { // Your app is missing the provider configuration dependency. // Most likely, you're missing the // "credentials-play-services-auth" module. } is CreateCredentialUnknownException -> ... is CreateCredentialCustomException -> { // You have encountered an error from a 3rd-party SDK. If you // make the API call with a request object that's a subclass of // CreateCustomCredentialRequest using a 3rd-party SDK, then you // should check for any custom exception type constants within // that SDK to match with e.type. Otherwise, drop or log the // exception. } else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}") } }
Java
public void createPasskey(String requestJson, boolean preferImmediatelyAvailableCredentials) { CreatePublicKeyCredentialRequest createPublicKeyCredentialRequest = // `requestJson` contains the request in JSON format. Uses the standard // WebAuthn web JSON spec. // `preferImmediatelyAvailableCredentials` defines whether you prefer // to only use immediately available credentials, not hybrid credentials, // to fulfill this request. This value is false by default. new CreatePublicKeyCredentialRequest( requestJson, preferImmediatelyAvailableCredentials); // Execute CreateCredentialRequest asynchronously to register credentials // for a user account. Handle success and failure cases with the result and // exceptions, respectively. credentialManager.createCredentialAsync( // Use an activity-based context to avoid undefined system // UI launching behavior requireActivity(), createPublicKeyCredentialRequest, cancellationSignal, executor, new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() { @Override public void onResult(CreateCredentialResponse result) { handleSuccessfulCreatePasskeyResult(result); } @Override public void onError(CreateCredentialException e) { if (e instanceof CreatePublicKeyCredentialDomException) { // Handle the passkey DOM errors thrown according to the // WebAuthn spec. handlePasskeyError(((CreatePublicKeyCredentialDomException)e).getDomError()); } else if (e instanceof CreateCredentialCancellationException) { // The user intentionally canceled the operation and chose not // to register the credential. } else if (e instanceof CreateCredentialInterruptedException) { // Retry-able error. Consider retrying the call. } else if (e instanceof CreateCredentialProviderConfigurationException) { // Your app is missing the provider configuration dependency. // Most likely, you're missing the // "credentials-play-services-auth" module. } else if (e instanceof CreateCredentialUnknownException) { } else if (e instanceof CreateCredentialCustomException) { // You have encountered an error from a 3rd-party SDK. If // you make the API call with a request object that's a // subclass of // CreateCustomCredentialRequest using a 3rd-party SDK, // then you should check for any custom exception type // constants within that SDK to match with e.type. // Otherwise, drop or log the exception. } else { Log.w(TAG, "Unexpected exception type " + e.getClass().getName()); } } } ); }
Formatta la richiesta JSON
Dopo aver creato una passkey, devi associarla all'account di un utente e memorizzare la chiave pubblica della passkey sul tuo server. Il seguente esempio di codice mostra come formattare la richiesta JSON quando crei una passkey.
Questo post del blog sull'implementazione dell'autenticazione senza interruzioni nelle tue app mostra come formattare la richiesta JSON quando crei le passkey e quando ti autentichi utilizzandole. Spiega inoltre perché le password non sono una soluzione di autenticazione efficace, come sfruttare le credenziali biometriche esistenti, come associare la tua app a un sito web di tua proprietà, come creare passkey e come autenticarsi utilizzando le passkey.
{
"challenge": "abc123",
"rp": {
"name": "Credential Manager example",
"id": "credential-manager-test.example.com"
},
"user": {
"id": "def456",
"name": "helloandroid@gmail.com",
"displayName": "helloandroid@gmail.com"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 1800000,
"attestation": "none",
"excludeCredentials": [
{"id": "ghi789", "type": "public-key"},
{"id": "jkl012", "type": "public-key"}
],
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
Imposta i valori per authenticatorAttachment
Il parametro authenticatorAttachment
può essere impostato solo al momento della creazione delle credenziali. Puoi specificare platform
, cross-platform
o nessun valore. Nella maggior parte dei casi,
non è consigliato alcun valore.
platform
: per registrare il dispositivo attuale dell'utente o chiedere a un utente con password di eseguire l'upgrade alle passkey dopo un accesso, impostaauthenticatorAttachment
suplatform
.cross-platform
: questo valore viene comunemente utilizzato per registrare le credenziali di autenticazione a due fattori e non viene utilizzato in un contesto di passkey.- Nessun valore: per offrire agli utenti la flessibilità di creare
le passkey sui loro dispositivi preferiti (ad esempio nelle impostazioni dell'account),
Il parametro
authenticatorAttachment
non deve essere specificato se un utente sceglie per aggiungere una passkey. Nella maggior parte dei casi, lasciare il parametro non specificato è la soluzione migliore .
Impedisci la creazione di passkey duplicate
Elenca gli ID delle credenziali nell'array facoltativo excludeCredentials
per impedire la creazione di una nuova passkey se ne esiste già una con lo stesso fornitore.
Gestire la risposta JSON
Il seguente snippet di codice mostra una risposta JSON di esempio per la creazione di un file credenziale della chiave. Scopri di più su come gestire la credenziale della chiave pubblica restituita.
{
"id": "KEDetxZcUfinhVi6Za5nZQ",
"type": "public-key",
"rawId": "KEDetxZcUfinhVi6Za5nZQ",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibmhrUVhmRTU5SmI5N1Z5eU5Ka3ZEaVh1Y01Fdmx0ZHV2Y3JEbUdyT0RIWSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A"
}
}
Verificare l'origine dal file JSON dei dati del cliente
origin
rappresenta l'applicazione o il sito web a cui è stata
proviene e viene utilizzata dalle passkey per proteggere gli utenti dagli attacchi phishing.
Il server della tua app deve verificare il client
rispetto a una lista consentita di app e siti web approvati. Se il server riceve una richiesta da un'app o un sito web di un'origine non riconosciuta, la richiesta deve essere rifiutata.
Nel caso del web, origin
riflette l'origine dello stesso sito in cui è stata eseguita l'autenticazione con le credenziali. Ad esempio, dato un URL di
https://www.example.com:8443/store?category=shoes#athletic
, origin
è
https://www.example.com:8443
.
Per le app per Android, l'agente utente imposta automaticamente origin
sulla firma dell'app chiamante. Questa firma deve essere verificata come corrispondenza sul server per convalidare il chiamante dell'API passkey. L'elemento origin
di Android è un URI derivato
dall'hash SHA-256 del certificato di firma dell'APK, ad esempio:
android:apk-key-hash:<sha256_hash-of-apk-signing-cert>
Gli hash SHA-256 dei certificati di firma di un archivio chiavi sono disponibili tramite: eseguendo questo comando nel terminale:
keytool -list -keystore <path-to-apk-signing-keystore>
Gli hash SHA-256 sono in formato esadecimale delimitato da due punti.
(91:F7:CB:F9:D6:81…
) e i valori origin
per Android hanno la codifica base64url.
Questo esempio Python mostra come convertire il formato hash in un modello
formato esadecimale separato da due punti:
import binascii
import base64
fingerprint = '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5'
print("android:apk-key-hash:" + base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
Sostituisci il valore di fingerprint
con il tuo valore. Ecco un esempio
risultato:
android:apk-key-hash:kffL-daBUxvHpY-4M8yhTavt5QnFEI2LsexohxrGPYU
Puoi quindi associare la stringa come origine consentita sul tuo server. Se disponi più certificati di firma, come certificati per il debug e il rilascio, o più app, quindi ripeti la procedura e accetta tutte queste origini come valide sul server.
Salvare la password di un utente
Se l'utente fornisce un nome utente e una password per un flusso di autenticazione nella tua app, puoi registrare una credenziale utente che può essere utilizzata per autenticare l'utente. Per farlo, crea un oggetto CreatePasswordRequest
:
Kotlin
fun registerPassword(username: String, password: String) { // Initialize a CreatePasswordRequest object. val createPasswordRequest = CreatePasswordRequest(id = username, password = password) // Create credential and handle result. coroutineScope.launch { try { val result = credentialManager.createCredential( // Use an activity based context to avoid undefined // system UI launching behavior. activityContext, createPasswordRequest ) handleRegisterPasswordResult(result) } catch (e: CreateCredentialException) { handleFailure(e) } } }
Java
void registerPassword(String username, String password) { // Initialize a CreatePasswordRequest object. CreatePasswordRequest createPasswordRequest = new CreatePasswordRequest(username, password); // Register the username and password. credentialManager.createCredentialAsync( // Use an activity-based context to avoid undefined // system UI launching behavior requireActivity(), createPasswordRequest, cancellationSignal, executor, new CredentialManagerCallback<CreateCredentialResponse, CreateCredentialException>() { @Override public void onResult(CreateCredentialResponse result) { handleResult(result); } @Override public void onError(CreateCredentialException e) { handleFailure(e); } } ); }
Supportare il recupero delle credenziali
Se un utente non ha più accesso a un dispositivo su cui aveva archiviato le sue credenziali, potrebbe dover eseguire il recupero da un backup online sicuro. Per scoprire di più su come supportare questa procedura di recupero delle credenziali, leggi la sezione "Recupero dell'accesso o aggiunta di nuovi dispositivi" di questo post del blog: Sicurezza delle passkey nel Gestore delle password di Google.
Aggiunta del supporto per gli strumenti di gestione delle password con URL noti degli endpoint delle passkey
Per un'integrazione perfetta e una compatibilità futura con password e credenziali strumenti di gestione delle passkey, consigliamo di aggiungere il supporto per gli endpoint delle passkey URL. Si tratta di un protocollo aperto che consente alle parti allineate di pubblicizzare formalmente i propri il supporto per le passkey e fornisce link diretti per la registrazione delle passkey gestione dei dispositivi.
- Per una terza parte attendibile all'indirizzo
https://example.com
, che ha un sito web e app per Android e iOS, l'URL noto saràhttps://example.com/.well-known/passkey-endpoints
. Quando viene eseguita una query sull'URL, la risposta deve utilizzare lo schema seguente
{ "enroll": "https://example.com/account/manage/passkeys/create" "manage": "https://example.com/account/manage/passkeys" }
Per fare in modo che il link venga aperto direttamente nella tua app anziché sul web, usa Link per app Android.
Per ulteriori dettagli, consulta la pagina di spiegazione sull'URL noto degli endpoint delle passkey su GitHub.
Aiuta gli utenti a gestire le proprie passkey mostrando il fornitore che le ha create
Uno dei problemi che gli utenti devono affrontare quando gestiscono più passkey associate a una determinata app è identificare la passkey corretta da modificare o eliminare. Per aiutare con questo problema, è consigliabile che le app e i siti web includano altri informazioni come il provider che ha creato la credenziale, la data di creazione e la data dell'ultimo utilizzo in un elenco di passkey nella schermata delle impostazioni dell'app. informazioni si ottiene esaminando il codice AAGUID associato con la passkey corrispondente. AAGUID è disponibile nei dati dell'autenticatore di una passkey.
Ad esempio, se un utente crea una passkey su un dispositivo Android utilizzando Gestore delle password di Google, l'RP riceve un AAGUID simile al seguente: "ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4". La parte coinvolta può annota la passkey nell'elenco per indicare che è stata creata utilizzando Gestore delle password di Google.
Per mappare un AAGUID a un provider di passkey, le parti soggette a limitazioni possono usare una community di repository di AAGUID. Cerca l'AAGUID nella sezione per trovare il nome e l'icona del provider di passkey.
Scopri di più sull'integrazione AAGUID.
Risolvere gli errori comuni
La tabella seguente mostra una serie di codici di errore e descrizioni comuni. fornisce alcune informazioni sulle loro cause:
Codice e descrizione errore | Causa |
---|---|
All'inizio dell'accesso non riuscito: 16: il chiamante è stato temporaneamente bloccato a causa di a troppe richieste di accesso annullate. | Se riscontri questo periodo di attesa di 24 ore durante lo sviluppo, puoi reimpostarlo svuotando lo spazio di archiviazione delle app di Google Play Services. In alternativa, per attivare/disattivare questo tempo di attesa su un dispositivo di test o un emulatore, vai all'app Telefono e inserisci il seguente codice:
|
All'inizio dell'accesso non riuscito: 8: errore interno sconosciuto. |
|
CreatePublicKeyCredentialDomEccezione: la richiesta in entrata non può essere convalidato | L'ID pacchetto dell'app non è registrato sul server. Convalida nell'integrazione lato server. |
CreateCredentialUnknownEccezione: durante il salvataggio della password, è stata trovata la password risposta all'errore con un tocco 16: Il salvataggio della password è stato ignorato da quando l'utente probabilmente viene richiesta con la compilazione automatica di Android | Questo errore si verifica solo su Android 13 e versioni precedenti e solo se Google è il provider di compilazione automatica. In questo caso, gli utenti visualizzano una richiesta di salvataggio da Riempimento automatico e la password viene salvata in Gestore delle password di Google. Tieni presente che le credenziali salvate utilizzando la Compilazione automatica Google vengono in modo bidirezionale con l'API Credential Manager. Di conseguenza, questo errore può essere ignorato. |
Risorse aggiuntive
Per scoprire di più sull'API Credential Manager e sulle passkey, consulta le seguenti risorse:
- Passkey UX Guide
- Video: come ridurre la dipendenza dalle password nelle app per Android con la passkey assistenza
- Codelab: scopri come semplificare i flussi di autenticazione utilizzando l'API Credential Manager nella tua app per Android
- App di esempio: CredentialManager