Consenti agli utenti di accedere con le loro credenziali salvate

Usa il client di accesso One Tap per richiedere l'autorizzazione all'utente per recuperare una delle credenziali utilizzate in precedenza per accedere alla tua app. Queste credenziali possono essere un Account Google o una combinazione di nome utente-password salvate con Google utilizzando Chrome, la compilazione automatica di Android o Smart Lock per password.

Interfaccia utente di accesso con un tocco

Quando le credenziali vengono recuperate, puoi utilizzarle per eseguire l'accesso alla tua app senza difficoltà.

Se l'utente non ha salvato alcuna credenziale, non viene visualizzata alcuna UI e puoi fornire la tua normale esperienza di disconnessione.

Dove devo utilizzare l'accesso con One Tap?

Se la tua app richiede agli utenti di accedere, visualizza l'UI di One Tap nella schermata di accesso. Questo può essere utile anche se hai già un pulsante "Accedi con Google": poiché l'interfaccia utente di One Tap può essere configurata in modo da mostrare solo le credenziali utilizzate in precedenza dall'utente per l'accesso, può essere utilizzato un promemoria per gli utenti che accedono raramente alla tua app e impediscono loro di creare accidentalmente nuovi account con la tua app.

Se l'accesso è facoltativo per la tua app, valuta la possibilità di utilizzare l'accesso One Tap su qualsiasi schermata che offre un'esperienza migliorata. Ad esempio, se gli utenti possono sfogliare i contenuti con la tua app senza aver eseguito l'accesso, ma possono pubblicare commenti o aggiungere articoli al carrello dopo l'accesso, si tratta di un contesto ragionevole per l'accesso a One Tap.

Le app facoltative di accesso devono utilizzare l'accesso One Tap anche nelle schermate di accesso per i motivi indicati sopra.

Prima di iniziare

1. Configura il client di accesso One Tap

Puoi configurare il client di accesso One Tap per consentire agli utenti di accedere utilizzando password salvate, Account Google salvati o una delle due opzioni. È consigliabile supportarli entrambi per attivare la creazione di account con un tocco per i nuovi utenti e per l'accesso automatico o con un tocco al maggior numero possibile di utenti di ritorno.

Se l'app utilizza l'accesso basato su password, utilizza setPasswordRequestOptions() per attivare le richieste di credenziali per password.

Se la tua app utilizza Accedi con Google, utilizza setGoogleIdTokenRequestOptions() per attivare e configurare le richieste di token ID Google:

  • Imposta l'ID client server sull'ID che hai creato nella console delle API di Google. Tieni presente che questo è l'ID client del tuo server, non il tuo ID client Android.

  • Configura il client in modo che filtri per account autorizzati. Quando attivi questa opzione, il client One Tap chiede agli utenti di accedere alla tua app solo con gli Account Google che hanno già utilizzato in passato. Questo può aiutare gli utenti ad accedere correttamente quando non sono sicuri se hanno già un account o quale Account Google hanno utilizzato e impedisce agli utenti di creare accidentalmente nuovi account con l'app.

  • Se vuoi consentire agli utenti di accedere automaticamente quando possibile, attiva la funzionalità con setAutoSelectEnabled(). L'accesso automatico è possibile se vengono soddisfatti i seguenti criteri:

    • L'utente ha salvato esattamente una credenziale per la tua app, ovvero una password salvata o un Account Google salvato.
    • L'utente non ha disattivato l'accesso automatico nelle sue impostazioni dell'Account Google.
  • Sebbene sia facoltativo, ti consigliamo vivamente di utilizzare un nonce per migliorare la sicurezza di accesso ed evitare attacchi di ripetizione. Utilizza setNonce per includere un nonce in ogni richiesta. Consulta la sezione Ottenere un nonce per i suggerimenti e ulteriori dettagli sulla generazione di un nonce.

Java

public class YourActivity extends AppCompatActivity {
  // ...

  private SignInClient oneTapClient;
  private BeginSignInRequest signInRequest;

  @Override
  public void onCreate(@Nullable Bundle savedInstanceState,
                       @Nullable PersistableBundle persistentState) {
      super.onCreate(savedInstanceState, persistentState);

      oneTapClient = Identity.getSignInClient(this);
      signInRequest = BeginSignInRequest.builder()
              .setPasswordRequestOptions(PasswordRequestOptions.builder()
                      .setSupported(true)
                      .build())
              .setGoogleIdTokenRequestOptions(GoogleIdTokenRequestOptions.builder()
                      .setSupported(true)
                      // Your server's client ID, not your Android client ID.
                      .setServerClientId(getString(R.string.default_web_client_id))
                      // Only show accounts previously used to sign in.
                      .setFilterByAuthorizedAccounts(true)
                      .build())
              // Automatically sign in when exactly one credential is retrieved.
              .setAutoSelectEnabled(true)
              .build();
      // ...
  }
  // ...
}

Kotlin

class YourActivity : AppCompatActivity() {
    // ...

    private lateinit var oneTapClient: SignInClient
    private lateinit var signInRequest: BeginSignInRequest

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oneTapClient = Identity.getSignInClient(this)
        signInRequest = BeginSignInRequest.builder()
            .setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder()
                .setSupported(true)
                .build())
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Only show accounts previously used to sign in.
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            // Automatically sign in when exactly one credential is retrieved.
            .setAutoSelectEnabled(true)
            .build()
        // ...
    }
    // ...
}

2. Verificare la presenza di un utente che ha eseguito l'accesso

Se la tua attività può essere utilizzata da un utente che ha eseguito l'accesso o da un utente che non ha eseguito l'accesso, controlla lo stato dell'utente prima di visualizzare l'UI di accesso One Tap.

Devi anche controllare se l'utente ha già rifiutato l'utilizzo dell'accesso One Tap chiudendo la richiesta o toccando l'esterno. Può essere semplice come una proprietà booleana dell'attività. Consulta la sezione Interrompere la visualizzazione dell'interfaccia utente di One Tap di seguito.

3. Visualizzare l'interfaccia utente di accesso One Tap

Se l'utente non ha eseguito l'accesso e non ha già rifiutato di utilizzare l'accesso One Tap, chiama il metodo beginSignIn() dell'oggetto client e collega gli ascoltatori al metodo Task che restituisce. In genere, le app lo fanno nel metodo onCreate() dell'attività o dopo le transizioni dello schermo quando utilizzano un'architettura con un'unica attività.

Il client One Tap chiamerà il listener di successo se l'utente ha credenziali salvate per la tua applicazione. Nel listener di successo, recupera l'intent in attesa dal risultato Task e passalo a startIntentSenderForResult() per avviare l'UI di accesso One Tap.

Se l'utente non ha credenziali salvate, il client One Tap chiamerà il listener di errore. In questo caso non è necessaria alcuna azione: puoi semplicemente continuare a presentare l'esperienza di disconnessione dell'app. Tuttavia, se supporti la registrazione One Tap, potresti iniziare questa procedura per un'esperienza di creazione dell'account senza interruzioni. Vedi Creare nuovi account con un tocco.

Java

oneTapClient.beginSignIn(signUpRequest)
        .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
            @Override
            public void onSuccess(BeginSignInResult result) {
                try {
                    startIntentSenderForResult(
                            result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
                            null, 0, 0, 0);
                } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                }
            }
        })
        .addOnFailureListener(this, new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // No saved credentials found. Launch the One Tap sign-up flow, or
                // do nothing and continue presenting the signed-out UI.
                Log.d(TAG, e.getLocalizedMessage());
            }
        });

Kotlin

oneTapClient.beginSignIn(signInRequest)
    .addOnSuccessListener(this) { result ->
        try {
            startIntentSenderForResult(
                result.pendingIntent.intentSender, REQ_ONE_TAP,
                null, 0, 0, 0, null)
        } catch (e: IntentSender.SendIntentException) {
            Log.e(TAG, "Couldn't start One Tap UI: ${e.localizedMessage}")
        }
    }
    .addOnFailureListener(this) { e ->
        // No saved credentials found. Launch the One Tap sign-up flow, or
        // do nothing and continue presenting the signed-out UI.
        Log.d(TAG, e.localizedMessage)
    }

4. Gestire la risposta dell'utente

La risposta dell'utente alla richiesta di accesso One Tap verrà segnalata alla tua app utilizzando il metodo onActivityResult() della tua attività. Se l'utente ha scelto di accedere, il risultato sarà una credenziale salvata. Se l'utente ha rifiutato di accedere, chiudendo la UI di One Tap o toccando al di fuori, il risultato verrà restituito con il codice RESULT_CANCELED. La tua app deve gestire entrambe le possibilità.

Accedere con le credenziali recuperate

Se l'utente ha scelto di condividere le credenziali con la tua app, puoi recuperarle passando i dati dell'intent da onActivityResult() al metodo getSignInCredentialFromIntent() del client One Tap. La credenziale avrà una proprietà googleIdToken non null se l'utente ha condiviso una credenziale Account Google con l'app o una proprietà password non null se l'utente ha condiviso una password salvata.

Utilizza le credenziali per eseguire l'autenticazione con il backend dell'app.

  • Se è stata recuperata una coppia nome utente e password, utilizzala per accedere allo stesso modo in cui faresti se l'utente li avesse forniti manualmente.
  • Se le credenziali dell'Account Google sono state recuperate, utilizza il token ID per eseguire l'autenticazione con il backend. Se hai scelto di utilizzare un nonce per evitare gli attacchi di ripetizione, controlla il valore di risposta sul server di backend. Vedi Autenticarsi con un backend utilizzando i token ID.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(data);
                  String idToken = credential.getGoogleIdToken();
                  String username = credential.getId();
                  String password = credential.getPassword();
                  if (idToken !=  null) {
                      // Got an ID token from Google. Use it to authenticate
                      // with your backend.
                      Log.d(TAG, "Got ID token.");
                  } else if (password != null) {
                      // Got a saved username and password. Use them to authenticate
                      // with your backend.
                      Log.d(TAG, "Got password.");
                  }
              } catch (ApiException e) {
                  // ...
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
             REQ_ONE_TAP -> {
                try {
                    val credential = oneTapClient.getSignInCredentialFromIntent(data)
                    val idToken = credential.googleIdToken
                    val username = credential.id
                    val password = credential.password
                    when {
                        idToken != null -> {
                            // Got an ID token from Google. Use it to authenticate
                            // with your backend.
                            Log.d(TAG, "Got ID token.")
                        }
                        password != null -> {
                            // Got a saved username and password. Use them to authenticate
                            // with your backend.
                            Log.d(TAG, "Got password.")
                        }
                        else -> {
                            // Shouldn't happen.
                            Log.d(TAG, "No ID token or password!")
                        }
                    }
                } catch (e: ApiException) {
                    // ...
                }
            }
        }
    }
    // ...
}

Interrompere la visualizzazione della UI One Tap

Se l'utente ha rifiutato di accedere, la chiamata al numero getSignInCredentialFromIntent() genererà un ApiException con un codice di stato CommonStatusCodes.CANCELED. In questo caso, devi disattivare temporaneamente l'interfaccia utente di accesso One Tap per non infastidire gli utenti con messaggi ripetuti. L'esempio seguente esegue questa operazione impostando una proprietà sull'attività, che utilizza per determinare se offrire all'utente l'accesso One Tap, ma puoi anche salvare un valore in SharedPreferences o utilizzare un altro metodo.

È importante implementare la propria limitazione di frequenza delle richieste di accesso One Tap. Se non lo fai e un utente annulla più richieste di seguito, il client One Tap non gli chiederà di farlo per le 24 ore successive.

Java

public class YourActivity extends AppCompatActivity {

  // ...
  private static final int REQ_ONE_TAP = 2;  // Can be any integer unique to the Activity.
  private boolean showOneTapUI = true;
  // ...

  @Override
  protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
      super.onActivityResult(requestCode, resultCode, data);

      switch (requestCode) {
          case REQ_ONE_TAP:
              try {
                  // ...
              } catch (ApiException e) {
                  switch (e.getStatusCode()) {
                      case CommonStatusCodes.CANCELED:
                          Log.d(TAG, "One-tap dialog was closed.");
                          // Don't re-prompt the user.
                          showOneTapUI = false;
                          break;
                      case CommonStatusCodes.NETWORK_ERROR:
                          Log.d(TAG, "One-tap encountered a network error.");
                          // Try again or just ignore.
                          break;
                      default:
                          Log.d(TAG, "Couldn't get credential from result."
                                  + e.getLocalizedMessage());
                          break;
                  }
              }
              break;
      }
  }
}

Kotlin

class YourActivity : AppCompatActivity() {

    // ...
    private val REQ_ONE_TAP = 2  // Can be any integer unique to the Activity
    private var showOneTapUI = true
    // ...

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            REQ_ONE_TAP -> {
                try {
                    // ...
                } catch (e: ApiException) {
                    when (e.statusCode) {
                        CommonStatusCodes.CANCELED -> {
                            Log.d(TAG, "One-tap dialog was closed.")
                            // Don't re-prompt the user.
                            showOneTapUI = false
                        }
                        CommonStatusCodes.NETWORK_ERROR -> {
                            Log.d(TAG, "One-tap encountered a network error.")
                            // Try again or just ignore.
                        }
                        else -> {
                            Log.d(TAG, "Couldn't get credential from result." +
                                " (${e.localizedMessage})")
                        }
                    }
                }
            }
        }
    }
    // ...
}

5. Gestire la disconnessione

Quando un utente si disconnette, chiama il metodo signOut() del client One Tap. Se chiami signOut(), l'accesso automatico viene disattivato fino a quando l'utente non accede di nuovo.

Anche se non utilizzi l'accesso automatico, questo passaggio è importante perché garantisce che, quando gli utenti escono dall'app, lo stato di autenticazione di tutte le API Play Services che usi venga reimpostato.

Passaggi successivi

Se hai configurato il client One Tap per il recupero delle credenziali Google, la tua app può ora ricevere token ID Google che rappresentano gli Account Google dei tuoi utenti. Scopri come puoi utilizzare questi token nel backend.

Se supporti Accedi con Google, puoi anche utilizzare il client One Tap per aggiungere flussi di creazione di account senza problemi alla tua app.