Użyj klienta logowania jednym dotknięciem, aby poprosić użytkownika o pozwolenie na pobranie jednego z danych, których używał wcześniej do logowania się w Twojej aplikacji. Może to być konto Google lub kombinacja nazwy użytkownika i hasła zapisane w Google przy użyciu Chrome, funkcji autouzupełniania w Androidzie lub funkcji Smart Lock na hasła.
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, nie zostanie wyświetlony interfejs użytkownika. Możesz też uruchomić normalne działanie, gdy użytkownik nie będzie zalogowany.
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. To może być przydatne, nawet jeśli masz już przycisk „Zaloguj się przez Google”, ponieważ możesz skonfigurować interfejs jednym dotknięciem tak, aby pokazywał tylko dane logowania używane wcześniej przez użytkownika, co może przypominać użytkownikom, którzy rzadko logowali się ostatnio, i zapobiegać przypadkowemu tworzeniu nowych kont w aplikacji.
Jeśli w Twojej aplikacji logowanie jest opcjonalne, spróbuj zalogować się jednym dotknięciem na dowolnym ekranie, którego obsługa po zalogowaniu się wygodniejsza. 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, taka sytuacja ma sens w przypadku logowania jednym dotknięciem.
Z powodów opisanych powyżej w aplikacjach, które opcjonalne wymagają logowania, na ekranach logowania należy też używać logowania jednym dotknięciem.
Zanim zaczniesz
- Skonfiguruj projekt w konsoli interfejsów API Google i projekt Androida w sposób opisany w artykule Pierwsze kroki z logowaniem jednym dotknięciem.
- Jeśli obsługujesz logowanie się na podstawie hasła, zoptymalizuj aplikację pod kątem autouzupełniania (lub użyj funkcji Smart Lock do haseł), aby użytkownicy po zalogowaniu mogli zapisywać swoje dane logowania.
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 tych rozwiązań, aby umożliwić nowym użytkownikom tworzenie kont jednym dotknięciem, a jednocześnie logowanie automatyczne lub logowanie jednym dotknięciem dla jak największej liczby powracających użytkowników.
Jeśli Twoja aplikacja korzysta z logowania się za pomocą hasła, użyj polecenia setPasswordRequestOptions()
, aby włączyć żądania danych logowania przy użyciu hasła.
Jeśli Twoja aplikacja używa Logowania przez Google, użyj setGoogleIdTokenRequestOptions()
, aby włączyć i skonfigurować żądania tokenów identyfikatora Google:
Ustaw identyfikator klienta serwera na identyfikator utworzony w konsoli interfejsów API Google. Pamiętaj, że jest to identyfikator klienta Twojego serwera, a nie identyfikatora klienta Androida.
Skonfiguruj filtrowanie klienta według autoryzowanych kont. Gdy włączysz tę opcję, klient jednym dotknięciem będzie tylko prosić użytkowników o zalogowanie się w Twojej aplikacji za pomocą kont Google, z których już korzystali. Ułatwi to użytkownikom logowanie się, gdy nie będą pewni, czy już mają konto lub którego konta Google używali, a także zapobiega przypadkowemu tworzeniu nowych kont w Twojej aplikacji.
Jeśli chcesz, aby użytkownicy w miarę możliwości logowali się automatycznie, włącz tę funkcję w
setAutoSelectEnabled()
. Logowanie automatyczne jest możliwe, gdy są spełnione te kryteria:- Użytkownik ma dokładnie 1 zapisany dane logowania do Twojej aplikacji. Oznacza to, że jedno zapisane hasło lub jedno zapisane konto Google.
- użytkownik nie wyłączył logowania automatycznego w ustawieniach konta Google;
Choć jest to opcjonalne, zalecamy użycie liczby jednorazowej, aby zwiększyć bezpieczeństwo logowania i uniknąć ponownych ataków. Aby do każdego żądania dołączyć liczbę jednorazową, użyj setNonce. W sekcji Uzyskiwanie liczby jednorazowej w SafetyNet znajdziesz sugestie i dodatkowe informacje o generowaniu 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 użytkownik jest zalogowany
Jeśli Twoja aktywność może zostać użyta przez zalogowanego lub niezalogowanego użytkownika, sprawdź jego stan, zanim wyświetli się interfejs logowania jednym dotknięciem.
Możesz też śledzić, czy użytkownik odmówił już użycia logowania jednym dotknięciem, zamykając potwierdzenie lub klikając poza nim. Może to być po prostu właściwość logiczna aktywności. (patrz sekcja Wyłączanie wyświetlania interfejsu 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
. Aplikacje zwykle robią to w metodzie onCreate()
aktywności lub po przeniesieniu ekranu, jeśli stosowana jest architektura z pojedynczą aktywnością.
Klient One Tap wywoła detektor sukcesu, jeśli użytkownik ma zapisane dane logowania do aplikacji. W detektorze sukcesu 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 kontynuować prezentację działania 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. 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
Reakcja użytkownika na prośbę o zalogowanie się jednym dotknięciem zostanie przekazana do aplikacji za pomocą metody onActivityResult()
Twojej 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 klikając poza nim, w wyniku pojawi się kod RESULT_CANCELED
. Aplikacja musi obsługiwać obie możliwości.
Zaloguj się za pomocą pobranych danych logowania
Jeśli użytkownik zdecyduje się udostępnić Twojej aplikacji dane logowania, możesz je pobrać, przekazując dane intencji z onActivityResult()
do metody getSignInCredentialFromIntent()
klienta One Tap. Jeśli użytkownik udostępnił aplikacji dane logowania do konta Google, dane logowania będą zawierać niepustą właściwość googleIdToken
, a jeśli użytkownik podał zapisane hasło, będzie mieć niepustą właściwość password
.
Użyj danych logowania, aby uwierzytelnić się w backendzie aplikacji.
- Jeśli para nazwy użytkownika i hasła została pobrana, użyj ich do zalogowania się w taki sam sposób, jak w przypadku, gdy 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ąć ponownego ataku, sprawdź wartość odpowiedzi na serwerze backendu. Zapoznaj się z artykułem Uwierzytelnianie w backendzie przy użyciu 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 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 należy tymczasowo wyłączyć interfejs logowania jednym dotknięciem, aby nie drażnić użytkowników powtarzającymi się monitami. W poniższym przykładzie jest to ustawienie właściwości w Aktywności, która służy do określania, czy użytkownik 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ę jednym dotknięciem. Jeśli tego nie zrobisz, a użytkownik anuluje kilka próśb z rzędu, klient One Tap nie wyświetli użytkownikowi prośby 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 One Tap.
Wywołanie signOut()
powoduje wyłączenie automatycznego logowania do momentu, gdy użytkownik zaloguje się ponownie.
Nawet jeśli nie korzystasz z logowania automatycznego, ten krok jest ważny, ponieważ dzięki niemu, gdy użytkownicy wylogują się z Twojej aplikacji, resetuje się też stan uwierzytelniania wszystkich używanych przez Ciebie interfejsów API Usług Google Play.
Dalsze kroki
Jeśli klient został skonfigurowany tak, aby pobierał dane logowania Google, 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 jednym dotknięciem, aby dodać do aplikacji bezproblemowe tworzenie kont.