Blocca negozio

Molti utenti gestiscono ancora le proprie credenziali quando configurano un nuovo Android dispositivo. Questo processo manuale può diventare impegnativo e spesso determina un'esperienza utente positiva. L'API Block Store, una libreria basata su Google Play Google Cloud, cerca di risolvere questo problema fornendo un modo per consentire alle app di salvare le credenziali utente senza la complessità o i rischi per la sicurezza associati al salvataggio le password degli utenti.

L'API Block Store consente alla tua app di archiviare i dati che può in un secondo momento recupera per eseguire nuovamente l'autenticazione degli utenti su un nuovo dispositivo. Ciò contribuisce a fornire una maggiore un'esperienza ottimale per gli utenti, in quanto non hanno bisogno di vedere una schermata di accesso quando avvii l'app per la prima volta sul nuovo dispositivo.

I vantaggi dell'utilizzo di Block Store includono quanto segue:

  • Soluzione di archiviazione delle credenziali criptata per sviluppatori. Le credenziali sono con crittografia end-to-end, se possibile.
  • Salva i token invece di nomi utente e password.
  • Elimina gli attriti dei flussi di accesso.
  • Libera gli utenti dall'onere di gestire password complesse.
  • Google verifica l'identità dell'utente.

Prima di iniziare

Per preparare l'app, completa i passaggi nelle sezioni seguenti.

Configura la tua app

Nel file build.gradle a livello di progetto, includi Maven di Google repositorysia in buildscript e allprojects sezioni:

buildscript {
  repositories {
    google()
    mavenCentral()
  }
}

allprojects {
  repositories {
    google()
    mavenCentral()
  }
}

Aggiungi Google Play Services dell'API Block Store al tuo file di build Gradle del modulo, che in genere è app/build.gradle:

dependencies {
  implementation 'com.google.android.gms:play-services-auth-blockstore:16.3.1'
}

Come funziona

Block Store consente agli sviluppatori di salvare e ripristinare array di massimo 16 byte. Ciò ti consente di salvare informazioni importanti relative alla sessione utente corrente e ti offre la flessibilità di salvare queste informazioni come preferisci. Questi dati possono essere protetti con crittografia end-to-end e l'infrastruttura che supporta l'archiviazione a blocchi si basa sull'infrastruttura Backup e ripristino.

Questa guida illustra il caso d'uso per salvare il token di un utente in Blocca archivio. I seguenti passaggi descrivono il funzionamento di un'app che utilizza Block Store:

  1. Durante il flusso di autenticazione dell'app, o in seguito, puoi memorizzare il token di autenticazione dell'utente in Block Store per il recupero in un secondo momento.
  2. Il token verrà archiviato localmente e potrà anche essere sottoposto a backup sul cloud, con crittografia end-to-end, se possibile.
  3. I dati vengono trasferiti quando l'utente avvia un flusso di ripristino su un nuovo dispositivo.
  4. Se l'utente ripristina l'app durante il flusso di ripristino, l'app potrà recupera il token salvato da Block Store sul nuovo dispositivo.

Salvataggio del token in corso...

Quando un utente accede alla tua app, puoi salvare il token di autenticazione generato per quell'utente in Blocca store. Puoi archiviare questo token utilizzando un valore di coppia di chiavi univoco che abbia un massimo di 4 kB per voce. Per archiviare il token, chiama setBytes() e setKey() su un'istanza di StoreBytesData.Builder per archiviare le credenziali dell'utente sul dispositivo di origine. Dopo aver salvato il token con l'archiviazione a blocchi, il token è criptato e archiviato localmente sul dispositivo.

L'esempio seguente mostra come salvare il token di autenticazione in il dispositivo locale:

Java

  BlockstoreClient client = Blockstore.getClient(this);
  byte[] bytes1 = new byte[] { 1, 2, 3, 4 };  // Store one data block.
  String key1 = "com.example.app.key1";
  StoreBytesData storeRequest1 = StoreBytesData.Builder()
          .setBytes(bytes1)
          // Call this method to set the key value pair the data should be associated with.
          .setKeys(Arrays.asList(key1))
          .build();
  client.storeBytes(storeRequest1)
    .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes"))
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

  val client = Blockstore.getClient(this)

  val bytes1 = byteArrayOf(1, 2, 3, 4) // Store one data block.
  val key1 = "com.example.app.key1"
  val storeRequest1 = StoreBytesData.Builder()
    .setBytes(bytes1) // Call this method to set the key value with which the data should be associated with.
    .setKeys(Arrays.asList(key1))
    .build()
  client.storeBytes(storeRequest1)
    .addOnSuccessListener { result: Int ->
      Log.d(TAG,
            "Stored $result bytes")
    }
    .addOnFailureListener { e ->
      Log.e(TAG, "Failed to store bytes", e)
    }

Usa token predefinito

I dati salvati utilizzando StoreBytes senza una chiave utilizzano la chiave predefinita BlockstoreClient.DEFAULT_BYTES_DATA_KEY.

Java

  BlockstoreClient client = Blockstore.getClient(this);
  // The default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
  byte[] bytes = new byte[] { 9, 10 };
  StoreBytesData storeRequest = StoreBytesData.Builder()
          .setBytes(bytes)
          .build();
  client.storeBytes(storeRequest)
    .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes"))
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

  val client = Blockstore.getClient(this);
  // the default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY.
  val bytes = byteArrayOf(1, 2, 3, 4)
  val storeRequest = StoreBytesData.Builder()
    .setBytes(bytes)
    .build();
  client.storeBytes(storeRequest)
    .addOnSuccessListener { result: Int ->
      Log.d(TAG,
            "stored $result bytes")
    }
    .addOnFailureListener { e ->
      Log.e(TAG, "Failed to store bytes", e)
    }

Recupero del token in corso...

In seguito, quando un utente segue il flusso di ripristino su un nuovo dispositivo, Google Play Services verifica prima l'utente e poi recupera il blocco Archivia i dati. L'utente ha già accettato di ripristinare i dati dell'app nell'ambito di flusso di ripristino, quindi non sono necessari consensi aggiuntivi. Quando l'utente apre la tua app, puoi richiedere il token da Block Store chiamando retrieveBytes() Il token recuperato può quindi essere utilizzato per mantenere l'accesso dell'utente sul nuovo dispositivo.

L'esempio seguente mostra come recuperare più token in base a chiavi specifiche.

Java

BlockstoreClient client = Blockstore.getClient(this);

// Retrieve data associated with certain keys.
String key1 = "com.example.app.key1";
String key2 = "com.example.app.key2";
String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to retrieve data stored without a key

List requestedKeys = Arrays.asList(key1, key2, key3); // Add keys to array
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(requestedKeys)
    .build();

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry entry : blockstoreDataMap.entrySet()) {
            Log.d(TAG, String.format(
                "Retrieved bytes %s associated with key %s.",
                new String(entry.getValue().getBytes()), entry.getKey()));
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

val client = Blockstore.getClient(this)

// Retrieve data associated with certain keys.
val key1 = "com.example.app.key1"
val key2 = "com.example.app.key2"
val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key

val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(requestedKeys)
  .build()

client.retrieveBytes(retrieveRequest)
  .addOnSuccessListener { result: RetrieveBytesResponse ->
    val blockstoreDataMap =
      result.blockstoreDataMap
    for ((key, value) in blockstoreDataMap) {
      Log.d(ContentValues.TAG, String.format(
        "Retrieved bytes %s associated with key %s.",
        String(value.bytes), key))
    }
  }
  .addOnFailureListener { e: Exception? ->
    Log.e(ContentValues.TAG,
          "Failed to store bytes",
          e)
  }

Recupero di tutti i token in corso.

Di seguito è riportato un esempio di come recuperare tutti i token salvati in BlockStore.

Java

BlockstoreClient client = Blockstore.getClient(this)

// Retrieve all data.
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setRetrieveAll(true)
    .build();

client.retrieveBytes(retrieveRequest)
    .addOnSuccessListener(
        result -> {
          Map blockstoreDataMap = result.getBlockstoreDataMap();
          for (Map.Entry entry : blockstoreDataMap.entrySet()) {
            Log.d(TAG, String.format(
                "Retrieved bytes %s associated with key %s.",
                new String(entry.getValue().getBytes()), entry.getKey()));
          }
        })
    .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));

Kotlin

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setRetrieveAll(true)
  .build()

client.retrieveBytes(retrieveRequest)
  .addOnSuccessListener { result: RetrieveBytesResponse ->
    val blockstoreDataMap =
      result.blockstoreDataMap
    for ((key, value) in blockstoreDataMap) {
      Log.d(ContentValues.TAG, String.format(
        "Retrieved bytes %s associated with key %s.",
        String(value.bytes), key))
    }
  }
  .addOnFailureListener { e: Exception? ->
    Log.e(ContentValues.TAG,
          "Failed to store bytes",
          e)
  }

Di seguito è riportato un esempio di come recuperare la chiave predefinita.

Java

BlockStoreClient client = Blockstore.getClient(this);
RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder()
    .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
    .build();
client.retrieveBytes(retrieveRequest);

Kotlin

val client = Blockstore.getClient(this)

val retrieveRequest = RetrieveBytesRequest.Builder()
  .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY))
  .build()
client.retrieveBytes(retrieveRequest)

Eliminazione dei token in corso...

L'eliminazione dei token da BlockStore potrebbe essere necessaria per i seguenti motivi:

  • L'utente esegue la procedura di uscita dell'utente.
  • Il token è stato revocato o non è valido.

Analogamente al recupero dei token, puoi specificare i token da eliminare impostando un array di chiavi da eliminare.

Di seguito è riportato un esempio relativo all'eliminazione di determinate chiavi.

Java

BlockstoreClient client = Blockstore.getClient(this);

// Delete data associated with certain keys.
String key1 = "com.example.app.key1";
String key2 = "com.example.app.key2";
String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to delete data stored without key

List requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array
DeleteBytesRequest deleteRequest = new DeleteBytesRequest.Builder()
      .setKeys(requestedKeys)
      .build();
client.deleteBytes(deleteRequest)

Kotlin

val client = Blockstore.getClient(this)

// Retrieve data associated with certain keys.
val key1 = "com.example.app.key1"
val key2 = "com.example.app.key2"
val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key

val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array

val retrieveRequest = DeleteBytesRequest.Builder()
      .setKeys(requestedKeys)
      .build()

client.deleteBytes(retrieveRequest)

Elimina tutti i token

Nell'esempio seguente vengono eliminati tutti i token attualmente salvati in BlockStore:

Java

// Delete all data.
DeleteBytesRequest deleteAllRequest = new DeleteBytesRequest.Builder()
      .setDeleteAll(true)
      .build();
client.deleteBytes(deleteAllRequest)
.addOnSuccessListener(result -> Log.d(TAG, "Any data found and deleted? " + result));

Kotlin

  val deleteAllRequest = DeleteBytesRequest.Builder()
  .setDeleteAll(true)
  .build()
client.deleteBytes(deleteAllRequest)
  .addOnSuccessListener { result: Boolean ->
    Log.d(TAG,
          "Any data found and deleted? $result")
  }

Crittografia end-to-end

Per rendere disponibile la crittografia end-to-end, il dispositivo deve essere con Android 9 o versioni successive e l'utente deve aver impostato un blocco schermo (PIN, sequenza o password) per il dispositivo. Puoi verificare se la crittografia sarà disponibile sul dispositivo chiamando il numero isEndToEndEncryptionAvailable().

L'esempio seguente mostra come verificare se la crittografia sarà disponibile durante backup sul cloud:

client.isEndToEndEncryptionAvailable()
        .addOnSuccessListener { result ->
          Log.d(TAG, "Will Block Store cloud backup be end-to-end encrypted? $result")
        }

Abilita backup sul cloud

Per abilitare il backup sul cloud, aggiungi setShouldBackupToCloud() al tuo StoreBytesData . Block Store esegue periodicamente il backup sul cloud dei byte archiviati setShouldBackupToCloud() è impostato su vero.

L'esempio seguente mostra come attivare il backup sul cloud solo quando il backup sul cloud con crittografia end-to-end:

val client = Blockstore.getClient(this)
val storeBytesDataBuilder = StoreBytesData.Builder()
        .setBytes(/* BYTE_ARRAY */)

client.isEndToEndEncryptionAvailable()
        .addOnSuccessListener { isE2EEAvailable ->
          if (isE2EEAvailable) {
            storeBytesDataBuilder.setShouldBackupToCloud(true)
            Log.d(TAG, "E2EE is available, enable backing up bytes to the cloud.")

            client.storeBytes(storeBytesDataBuilder.build())
                .addOnSuccessListener { result ->
                  Log.d(TAG, "stored: ${result.getBytesStored()}")
                }.addOnFailureListener { e ->
                  Log.e(TAG, “Failed to store bytes”, e)
                }
          } else {
            Log.d(TAG, "E2EE is not available, only store bytes for D2D restore.")
          }
        }

Come eseguire il test

Per testare il ripristino, utilizza i seguenti metodi durante lo sviluppo dei flussi.

Disinstallazione/reinstallazione sullo stesso dispositivo

Se l'utente abilita i servizi di backup (può essere selezionato in Impostazioni > Google > Backup), l'opzione Blocca dati dello store è persistenti in tutte le fasi di disinstallazione/reinstallazione dell'app.

Per verificare, puoi seguire questi passaggi:

  1. Integra l'API BlockStore nella tua app di test.
  2. Utilizza l'app di test per richiamare l'API BlockStore per archiviare i dati.
  3. Disinstalla l'app di test e reinstalla l'app sullo stesso dispositivo.
  4. Usa l'app di prova per richiamare l'API BlockStore e recuperare i dati.
  5. Verifica che i byte recuperati corrispondano a quelli archiviati in precedenza la disinstallazione.

Da dispositivo a dispositivo

Nella maggior parte dei casi, sarà necessario ripristinare i dati di fabbrica del dispositivo di destinazione. Puoi quindi accedi al flusso di ripristino wireless di Android. o Google cavo di ripristino (per i dispositivi supportati).

Ripristino nel cloud

  1. Integra l'API Blockstore nella tua app di test. L'app di prova deve essere inviati al Play Store.
  2. Sul dispositivo di origine, utilizza l'app di test per richiamare l'API Blockstore per l'archiviazione e i tuoi dati, con IfBackUpToCloud impostato su true.
  3. Per i dispositivi O e versioni successive, puoi attivare manualmente un backup sul cloud di Block Store: vai a Impostazioni > Google > Backup, fai clic sul pulsante "Esegui backup ora".
    1. Per verificare che il backup sul cloud di Block Store sia riuscito, puoi:
      1. Al termine del backup, cerca le righe di log con tag "CloudSyncBpTkSvc".
      2. Dovresti vedere righe come questa: "......, CloudSyncBpTkSvc: sync risultato: SUCCESS, ..., dimensione caricata: XXX byte ..."
    2. Dopo un backup sul cloud di Block Store, viene applicato un periodo di "raffreddamento" di 5 minuti. Entro quei 5 minuti, fare clic sul pulsante "Esegui il backup ora" non si attiverà un altro backup nel cloud di Block Store.
  4. Ripristina i dati di fabbrica del dispositivo di destinazione e segui un flusso di ripristino nel cloud. Seleziona per ripristinare l'app di test durante il flusso di ripristino. Per ulteriori informazioni Flussi di ripristino del cloud, vedi Flussi di ripristino del cloud supportati.
  5. Sul dispositivo di destinazione, utilizza l'app di test per richiamare l'API Blockstore recuperare i dati.
  6. Verifica che i byte recuperati corrispondano a quelli archiviati nel dispositivo di origine.

Requisiti del dispositivo

Crittografia end-to-end

  • La crittografia end-to-end è supportata su dispositivi con Android 9 (API 29) e versioni successive.
  • Per attivare la crittografia end-to-end e criptare correttamente i dati dell'utente, sul dispositivo deve essere impostato un blocco schermo con un PIN, una sequenza o una password.

Flusso di ripristino da dispositivo a dispositivo

Per il ripristino da dispositivo a dispositivo, devi avere un dispositivo di origine e un dispositivo di destinazione. Questi saranno i due dispositivi su cui verranno trasferiti i dati.

Per eseguire il backup, i dispositivi di origine devono eseguire Android 6 (API 23) o versioni successive.

Scegli come target i dispositivi con Android 9 (API 29) e versioni successive per poter eseguire il ripristino.

Ulteriori informazioni sul flusso di ripristino da dispositivo a dispositivo sono disponibili qui.

Flusso di backup e ripristino nel cloud

Il backup e il ripristino sul cloud richiederanno un dispositivo di origine e un dispositivo di destinazione.

Per eseguire il backup, i dispositivi di origine devono eseguire Android 6 (API 23) o versioni successive.

I dispositivi di target sono supportati in base ai fornitori. I dispositivi Pixel possono utilizzare questa funzionalità a partire da Android 9 (API 29) e tutti gli altri dispositivi devono eseguire Android 12 (API 31) o versioni successive.