Logowanie użytkowników przy użyciu zapisanych danych logowania

Użyj klienta logowania jednym dotknięciem, aby poprosić użytkownika o pozwolenie na pobranie jednego z danych logowania używanych wcześniej do logowania się w Twojej aplikacji. Mogą to być konto Google lub kombinacja nazwy użytkownika i hasła zapisane w Google przy użyciu Chrome, autouzupełniania w Androidzie lub funkcji Smart Lock na hasła.

Interfejs logowania jednym dotknięciem

Gdy dane logowania zostaną pobrane, możesz ich użyć do bezproblemowego logowania użytkownika w aplikacji.

Jeśli użytkownik nie zapisał żadnych danych logowania, interfejs użytkownika nie zostanie wyświetlony, a wylogowanie się odbywa się normalnie.

Gdzie należy używać logowania jednym dotknięciem?

Jeśli Twoja aplikacja wymaga od użytkowników logowania, wyświetl interfejs jednym dotknięciem na ekranie logowania. Może to być przydatne, nawet jeśli masz już przycisk „Zaloguj się przez Google”, ponieważ interfejs jednym dotknięciem możesz skonfigurować tak, aby wyświetlały się tylko dane logowania, których użytkownik wcześniej się logował, co może przypominać użytkownikom, którzy rzadko logowali się ostatnio, i zapobiegać przypadkowemu tworzeniu nowych kont w Twojej aplikacji.

Jeśli w Twojej aplikacji logowanie jest opcjonalne, rozważ logowanie się jednym dotknięciem na dowolnym ekranie, który ma lepsze wrażenia po zalogowaniu. Jeśli na przykład użytkownicy mogą przeglądać treści w Twojej aplikacji bez logowania się na konto, ale po zalogowaniu się mogą publikować komentarze lub dodawać produkty do koszyka, będzie to miało sens w przypadku logowania jednym dotknięciem.

Z powodów opisanych powyżej aplikacje opcjonalne wymagające logowania powinny też korzystać z logowania jednym dotknięciem na swoich ekranach logowania.

Zanim zaczniesz

1. Konfigurowanie klienta logowania jednym dotknięciem

Możesz skonfigurować klienta logowania jednym dotknięciem, aby logował użytkowników przy użyciu zapisanych haseł lub zapisanych kont Google. (Zalecamy korzystanie z obu rozwiązań, aby umożliwić tworzenie kont jednym dotknięciem dla nowych użytkowników oraz logowanie automatyczne lub logowanie jednym kliknięciem w przypadku jak największej liczby powracających użytkowników).

Jeśli Twoja aplikacja wykorzystuje logowanie na podstawie hasła, użyj setPasswordRequestOptions(), aby włączyć żądania danych logowania.

Jeśli Twoja aplikacja używa Logowania przez Google, za pomocą setGoogleIdTokenRequestOptions() włącz i skonfiguruj żądania tokena identyfikatora Google:

  • Ustaw identyfikator klienta serwera na identyfikator utworzony w konsoli interfejsów API Google. Pamiętaj, że jest to identyfikator klienta serwera, a nie identyfikatora klienta Androida.

  • Skonfiguruj klienta, aby filtrował według autoryzowanych kont. Gdy włączysz tę opcję, klient One Tap będzie prosić użytkowników tylko o zalogowanie się w aplikacji za pomocą kont Google, które były już wcześniej używane. Ułatwi to użytkownikom logowanie się, gdy nie będą pewni, czy już je mają lub którego konta Google używali. Zapobiega też przypadkowemu tworzeniu nowych kont w Twojej aplikacji.

  • Jeśli chcesz, aby użytkownicy logowali się automatycznie, gdy to możliwe, włącz tę funkcję za pomocą setAutoSelectEnabled(). Logowanie automatyczne jest możliwe, gdy są spełnione te kryteria:

    • Użytkownik ma dokładnie 1 zapisane dane logowania do Twojej aplikacji. Oznacza to, że jedno zapisane hasło lub jedno zapisane konto Google.
    • użytkownik nie wyłączył automatycznego logowania w ustawieniach konta Google;
  • Chociaż jest to opcjonalne, zalecamy jednak rozważenie użycia liczb jednorazowych, aby poprawić bezpieczeństwo logowania i uniknąć ataków typu replay. Aby w każdym żądaniu umieścić liczbę jednorazową, użyj setNonce. Zapoznaj się z sekcją Uzyskiwanie liczby jednorazowej na stronie SafetyNet, aby uzyskać sugestie i dodatkowe informacje na temat generowania liczby jednorazowej.

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. Sprawdzanie, czy jest zalogowany użytkownik

Jeśli zalogowany lub niezalogowany użytkownik może użyć Twojej aktywności, sprawdź stan użytkownika, zanim wyświetli się interfejs logowania jednym dotknięciem.

Trzeba też sprawdzić, czy użytkownik odmówił już logowania jednym dotknięciem, zamykając potwierdzenie lub klikając ekran poza nim. Może to być tak prosta jaka jest wartość logiczna aktywności. (patrz sekcja Wyłączanie wyświetlania interfejsu użytkownika jednym dotknięciem poniżej).

3. Wyświetl interfejs logowania jednym dotknięciem

Jeśli użytkownik nie jest zalogowany i nie zrezygnował jeszcze z logowania jednym dotknięciem, wywołaj metodę beginSignIn() obiektu klienta i dołącz detektory do zwróconego elementu Task. W przypadku architektury z pojedynczym działaniem aplikacje zwykle robią to w metodzie onCreate() aktywności lub po przejściu ekranu.

Klient One Tap wywoła detektor sukcesu, jeśli użytkownik ma zapisane dane logowania do aplikacji. W tym celu pobierz oczekującą intencję z wyniku Task i przekaż ją do startIntentSenderForResult(), aby uruchomić interfejs logowania jednym dotknięciem.

Jeśli użytkownik nie ma żadnych zapisanych danych logowania, klient One Tap wywoła detektor błędów. W takim przypadku nie musisz nic robić: możesz nadal korzystać z aplikacji po wylogowaniu się. Jeśli jednak obsługujesz rejestrację jednym dotknięciem, możesz rozpocząć ten proces tutaj, aby ułatwić sobie tworzenie konta. Więcej informacji znajdziesz w artykule Tworzenie nowych kont jednym kliknięciem.

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. Obsługa odpowiedzi użytkownika

Reakcja użytkownika na prośbę o zalogowanie się jednym dotknięciem jest przekazywana do aplikacji za pomocą metody onActivityResult() związanej z aktywnością. Jeśli użytkownik zdecyduje się się zalogować, zostaną zapisane dane logowania. Jeśli użytkownik odmówił zalogowania się, zamykając interfejs jednym dotknięciem lub dotykając go poza nim, powrót do wyniku z kodem RESULT_CANCELED. Aplikacja musi obsługiwać obie te możliwości.

Zaloguj się przy użyciu pobranych danych logowania

Jeśli użytkownik udostępnił dane logowania Twojej aplikacji, możesz je pobrać, przekazując dane intencji z onActivityResult() do metody getSignInCredentialFromIntent() klienta One Tap. Dane logowania będą miały niezerową właściwość googleIdToken, jeśli użytkownik udostępnił dane logowania do konta Google, lub właściwość password, jeśli użytkownik podał zapisane hasło.

Użyj danych logowania, aby uwierzytelnić się w backendzie aplikacji.

  • Po pobraniu pary nazwy użytkownika i hasła użyj ich do zalogowania się w taki sam sposób, w jaki użytkownik podałby je ręcznie.
  • Jeśli dane logowania na konto Google zostały pobrane, użyj tokena identyfikatora, aby uwierzytelnić się w backendzie. Jeśli chcesz używać liczby jednorazowej, aby uniknąć ponownych ataków, sprawdź wartość odpowiedzi na serwerze backendu. Zobacz Uwierzytelnianie za pomocą backendu przy użyciu tokenów identyfikatorów.

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) {
                    // ...
                }
            }
        }
    }
    // ...
}

Przestań wyświetlać interfejs jednym dotknięciem

Jeśli użytkownik odmówił zalogowania się, połączenie z numerem getSignInCredentialFromIntent() spowoduje zgłoszenie błędu ApiException z kodem stanu CommonStatusCodes.CANCELED. W takim przypadku wyłącz tymczasowo interfejs logowania jednym dotknięciem, aby nie denerwować użytkowników powtarzającymi się prośbami. W przykładzie poniżej można ustawić właściwość w Aktywności, która określa, czy ma oferować użytkownikowi logowanie jednym dotknięciem. Możesz też zapisać wartość w SharedPreferences lub użyć innej metody.

Ważne jest, aby wdrożyć własne ograniczenie częstotliwości próśb o zalogowanie się za pomocą jednego dotknięcia. Jeśli tego nie zrobisz, a użytkownik anuluje kilka próśb z rzędu, klient One Tap nie poprosi użytkownika przez następne 24 godziny.

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. Obsługa wylogowania

Gdy użytkownik wyloguje się z aplikacji, wywołaj metodę signOut() klienta One Tap. Wywołanie signOut() spowoduje wyłączenie automatycznego logowania, dopóki użytkownik nie zaloguje się ponownie.

Nawet jeśli nie korzystasz z logowania automatycznego, jest to ważne, ponieważ dzięki niemu, gdy użytkownicy wylogują się z aplikacji, resetuje się też stan uwierzytelniania używanych przez Ciebie interfejsów API usług Google Play.

Dalsze kroki

Jeśli masz skonfigurowany klient One Tap tak, aby pobierał dane logowania Google, Twoja aplikacja może teraz uzyskiwać tokeny tożsamości Google reprezentujące konta Google użytkowników. Dowiedz się, jak używać tych tokenów w backendzie.

Jeśli obsługujesz Logowanie przez Google, możesz też użyć klienta One Tap, aby dodać płynny proces tworzenia konta w aplikacji.