Użyj klienta logowania jednym dotknięciem, aby poprosić użytkownika o zezwolenie na pobranie jednego z danych logowania, których wcześniej używał do logowania się w Twojej aplikacji. Mogą to być konto Google lub kombinacja nazwy użytkownika i hasła zapisana przez użytkownika w Google za pomocą autouzupełniania w Chrome lub na Androidzie albo Smart Lock do haseł.
Gdy dane logowania zostaną pobrane, możesz ich użyć, aby bezproblemowo zalogować użytkownika w aplikacji.
Jeśli użytkownik nie zapisał żadnych danych logowania, nie wyświetli się żaden interfejs i możesz zapewnić mu standardowe środowisko po wylogowaniu.
Gdzie mogę używać logowania jednym dotknięciem?
Jeśli aplikacja wymaga zalogowania, wyświetl interfejs jedno dotknięcie na ekranie logowania. Może to być przydatne nawet wtedy, gdy masz już przycisk „Zaloguj się przez Google”: interfejs logowania jednym dotknięciem można skonfigurować tak, aby wyświetlał tylko dane logowania, których użytkownik używał wcześniej. Może to przypominać użytkownikom, którzy rzadko się logują, jak logowali się ostatnim razem, i zapobiegać przypadkowemu tworzeniu nowych kont w Twojej aplikacji.
Jeśli logowanie w aplikacji jest opcjonalne, rozważ użycie logowania jednym dotknięciem na dowolnym ekranie, na którym logowanie zwiększa komfort korzystania z aplikacji. Jeśli na przykład użytkownicy mogą przeglądać treści w aplikacji bez logowania, ale mogą dodawać komentarze lub produkty do koszyka na zakupy tylko po zalogowaniu, to jest to odpowiedni kontekst dla logowania jednym kliknięciem.
Aplikacje, w których logowanie jest opcjonalne, powinny też używać logowania jednym dotknięciem na ekranach logowania z powodów podanych powyżej.
Zanim zaczniesz
- Skonfiguruj projekt w Konsoli interfejsów API Google i projekt aplikacji na Androida zgodnie z instrukcjami w artykule Rozpoczynanie korzystania z logowania jednym kliknięciem.
- Jeśli obsługujesz logowanie za pomocą hasła, zoptymalizuj aplikację pod kątem autouzupełniania (lub użyj Smart Lock na hasła), aby użytkownicy mogli zapisywać dane logowania po zalogowaniu się.
1. Konfigurowanie klienta logowania jednym dotknięciem
Możesz skonfigurować klienta logowania jednym dotknięciem tak, aby logował użytkowników za pomocą zapisanych haseł, zapisanych kont Google lub obu tych metod. (Zalecamy obsługę obu tych opcji, aby umożliwić nowym użytkownikom tworzenie konta jednym kliknięciem, a jak największej liczbie powracających użytkowników – automatyczne logowanie lub logowanie jednym kliknięciem).
Jeśli aplikacja używa logowania opartego na haśle, użyj setPasswordRequestOptions(), aby włączyć żądania danych logowania opartych na haśle.
Jeśli Twoja aplikacja korzysta z Logowania przez Google, użyj setGoogleIdTokenRequestOptions(), aby włączyć i skonfigurować żą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 identyfikator klienta Androida.
Skonfiguruj klienta, aby filtrować według autoryzowanych kont. Gdy włączysz tę opcję, klient logowania jednym dotknięciem będzie wyświetlać użytkownikom prośbę o zalogowanie się w aplikacji za pomocą kont Google, których używali już w przeszłości. Dzięki temu użytkownicy będą mogli się zalogować, nawet jeśli nie mają pewności, czy mają już konto lub którego konta Google użyli. Zapobiegnie to też przypadkowemu tworzeniu przez użytkowników nowych kont w Twojej aplikacji.
Jeśli chcesz, aby użytkownicy logowali się automatycznie, gdy jest to możliwe, włącz tę funkcję za pomocą
setAutoSelectEnabled(). Logowanie automatyczne jest możliwe, gdy spełnione są te kryteria:- Użytkownik ma dokładnie 1 zapisane dane logowania do Twojej aplikacji, czyli 1 zapisane hasło lub 1 zapisane konto Google.
- Użytkownik nie wyłączył logowania automatycznego w ustawieniach konta Google.
Chociaż nie jest to wymagane, zdecydowanie zalecamy używanie liczby jednorazowej, aby zwiększyć bezpieczeństwo logowania i uniknąć ataków typu replay. Użyj funkcji setNonce, aby dołączać do każdego żądania wartość nonce. Więcej informacji o generowaniu wartości nonce znajdziesz w sekcji Uzyskiwanie wartości nonce w artykule o SafetyNet.
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 użytkownik jest zalogowany
Jeśli Twoja aktywność może być używana przez zalogowanego lub wylogowanego użytkownika, przed wyświetleniem interfejsu logowania jednym kliknięciem sprawdź stan użytkownika.
Musisz też śledzić, czy użytkownik odrzucił logowanie jednym kliknięciem, zamykając okno lub klikając poza nim. Może to być prosta właściwość logiczna aktywności. (Patrz Przestań wyświetlać interfejs jedno dotknięcie poniżej).
3. Wyświetlanie interfejsu logowania jednym dotknięciem
Jeśli użytkownik nie jest zalogowany i nie odrzucił jeszcze logowania jednym kliknięciem, wywołaj metodę beginSignIn() obiektu klienta i dołącz do zwracanego przez nią obiektu Task detektory. Aplikacje zwykle robią to w metodzie onCreate() aktywności lub po przejściach między ekranami, gdy używana jest architektura z jedną aktywnością.
Klient One Tap wywoła detektor powodzenia, jeśli użytkownik ma zapisane dane logowania do Twojej aplikacji. W detektorze powodzenia pobierz oczekujący zamiar z Task wyniku i przekaż go do startIntentSenderForResult(), aby uruchomić interfejs logowania One Tap.
Jeśli użytkownik nie ma zapisanych danych logowania, klient jedno dotknięcie wywoła detektor błędu. W takim przypadku nie musisz nic robić – możesz po prostu nadal wyświetlać aplikację w wersji dla użytkowników, którzy nie są zalogowani. Jeśli jednak obsługujesz rejestrację jednym kliknięciem, możesz rozpocząć ten proces tutaj, aby zapewnić użytkownikom płynne tworzenie konta. Zobacz 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
Odpowiedź użytkownika na prośbę o logowanie jednym kliknięciem zostanie przekazana do aplikacji za pomocą metody onActivityResult() aktywności. Jeśli użytkownik zdecyduje się zalogować, wynikiem będzie zapisany certyfikat. Jeśli użytkownik odmówił logowania, zamykając interfejs jedno dotknięcie lub klikając poza nim, wynik zostanie zwrócony z kodem RESULT_CANCELED. Aplikacja musi obsługiwać obie te możliwości.
Logowanie się za pomocą odzyskanych danych logowania
Jeśli użytkownik zdecyduje się udostępnić dane logowania Twojej aplikacji, możesz je pobrać, przekazując dane intencji z onActivityResult() do metody getSignInCredentialFromIntent() klienta jedno dotknięcie. Jeśli użytkownik udostępnił Twojej aplikacji dane logowania do konta Google, właściwość googleIdToken będzie miała wartość inną niż null. Jeśli użytkownik udostępnił zapisane hasło, właściwość password będzie miała wartość inną niż null.
Użyj danych logowania, aby uwierzytelnić się w backendzie aplikacji.
- Jeśli udało się pobrać parę nazwy użytkownika i hasła, użyj jej do zalogowania się w taki sam sposób, jak w przypadku ręcznego podania tych danych przez użytkownika.
Jeśli dane logowania do konta Google zostały pobrane, użyj tokena identyfikatora do uwierzytelnienia w backendzie. Jeśli używasz wartości nonce, aby zapobiegać atakom typu replay, sprawdź wartość odpowiedzi na serwerze backendu. Zobacz Uwierzytelnianie na backendzie za pomocą tokenów tożsamości.
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 logowania jednym dotknięciem
Jeśli użytkownik odmówi logowania, wywołanie funkcji getSignInCredentialFromIntent()
zgłosi błąd ApiException z kodem stanu CommonStatusCodes.CANCELED.
W takiej sytuacji tymczasowo wyłącz interfejs logowania jednym kliknięciem, aby nie irytować użytkowników powtarzającymi się prośbami. W tym przykładzie osiągamy ten cel, ustawiając właściwość w obiekcie Activity, która służy do określania, czy zaoferować użytkownikowi logowanie jednym kliknięciem. Możesz jednak zapisać wartość w SharedPreferences lub użyć innej metody.
Ważne jest, aby wdrożyć własne ograniczanie liczby żądań promptów logowania jednym dotknięciem. Jeśli tego nie zrobisz, a użytkownik anuluje kilka kolejnych promptów, klient jedno dotknięcie nie będzie wyświetlać promptów 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 wylogowywania
Gdy użytkownik wyloguje się z aplikacji, wywołaj metodę signOut() klienta jedno dotknięcie.
Wywołanie funkcji signOut() wyłącza logowanie automatyczne do momentu ponownego zalogowania się użytkownika.
Nawet jeśli nie używasz logowania automatycznego, ten krok jest ważny, ponieważ zapewnia, że gdy użytkownicy wylogują się z Twojej aplikacji, zresetowany zostanie też stan uwierzytelniania wszystkich używanych przez Ciebie interfejsów API Usług Google Play.
Dalsze kroki
Jeśli skonfigurowano klienta jedno dotknięcie do pobierania danych logowania Google, aplikacja może teraz uzyskiwać tokeny identyfikatora Google, które reprezentują konta Google użytkowników. Dowiedz się, jak używać tych tokenów na backendzie.
Jeśli obsługujesz Logowanie przez Google, możesz też użyć klienta jedno dotknięcie, aby dodać do aplikacji płynne procesy tworzenia konta.