Используйте клиент входа через One Tap, чтобы запросить у пользователя разрешение на получение одних из учетных данных, которые он ранее использовал для входа в ваше приложение. Это может быть аккаунт Google или комбинация имени пользователя и пароля, сохраненная в Google с помощью Chrome, автозаполнения Android или Smart Lock для паролей.
После успешного получения учетных данных вы можете использовать их для беспрепятственного входа пользователя в ваше приложение.
Если пользователь не сохранил учетные данные, интерфейс не будет показан, и вы сможете предоставить обычный интерфейс для выхода из системы.
Где следует использовать вход через One Tap?
Если в вашем приложении требуется вход, добавьте интерфейс One Tap на экран входа. Это может быть полезно, даже если у вас уже есть кнопка "Войти с аккаунтом Google". Поскольку интерфейс One Tap можно настроить так, чтобы в нем показывались только учетные данные, которые пользователь ранее использовал для входа, он может напоминать пользователям, которые редко входят в систему, о том, как они входили в последний раз, и предотвращать случайное создание новых аккаунтов в вашем приложении.
Если вход в аккаунт необязателен, рекомендуем использовать вход через One Tap на всех экранах, где вход в аккаунт может улучшить взаимодействие с приложением. Например, если пользователи могут просматривать контент в вашем приложении без входа в аккаунт, но для публикации комментариев или добавления товаров в корзину им нужно войти в аккаунт, то в этом случае вход через One Tap будет уместен.
В приложениях, где вход необязателен, также рекомендуется использовать One Tap на экранах входа по тем же причинам.
Подготовка
- Настройте проект в консоли Google Cloud и проект для Android, как описано в статье Начало работы с входом через One Tap.
- Если вы поддерживаете вход с помощью пароля, оптимизируйте приложение для автозаполнения (или используйте Smart Lock для паролей), чтобы пользователи могли сохранять свои пароли после входа.
1. Настройте клиент для входа через One Tap
Вы можете настроить клиент входа через One Tap так, чтобы пользователи входили с помощью сохраненных паролей, сохраненных аккаунтов Google или обоих способов. Рекомендуется поддерживать оба варианта, чтобы новые пользователи могли создавать аккаунты одним нажатием, а вернувшиеся пользователи – входить в них автоматически или одним нажатием.
Если в вашем приложении используется вход по паролю, включите запросы учетных данных с помощью setPasswordRequestOptions().
Если в вашем приложении используется вход с аккаунтом Google, включите и настройте запросы токенов идентификации Google с помощью setGoogleIdTokenRequestOptions():
Укажите идентификатор клиента сервера, созданный в консоли Google Cloud. Обратите внимание, что это идентификатор клиента сервера, а не Android.
Настройте клиент так, чтобы он фильтровал данные по авторизованным аккаунтам. Если вы включите этот параметр, One Tap будет предлагать пользователям войти в ваше приложение только с помощью аккаунтов Google, которые они уже использовали в прошлом. Это поможет пользователям войти в систему, если они не уверены, есть ли у них аккаунт или какой аккаунт Google они использовали, и предотвратит случайное создание новых аккаунтов в вашем приложении.
Если вы хотите, чтобы пользователи входили в аккаунт автоматически, включите эту функцию с помощью
setAutoSelectEnabled(). Автоматический вход возможен, если выполняются следующие условия:- Для вашего приложения у пользователя сохранены только одни учетные данные, то есть один пароль или один аккаунт Google.
- Пользователь не отключил автоматический вход в настройках аккаунта Google.
Хотя это необязательно, мы настоятельно рекомендуем использовать однократно используемое число, чтобы повысить безопасность входа и избежать атак повторного воспроизведения. Используйте setNonce, чтобы включить одноразовый код в каждый запрос. Дополнительную информацию о создании одноразового кода можно найти в разделе Получение одноразового кода документации 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. Проверьте, выполнен ли вход в аккаунт
Если ваше действие может использоваться как пользователем, вошедшим в аккаунт, так и пользователем, не вошедшим в аккаунт, проверьте статус пользователя, прежде чем показывать интерфейс входа через One Tap.
Также следует отслеживать, отказался ли пользователь от входа через One Tap, закрыв запрос или нажав за его пределами. Это может быть логическое свойство вашего действия. (см. раздел Как отключить показ интерфейса One Tap ниже).
3. Как показать интерфейс входа через One Tap
Если пользователь не вошел в аккаунт и не отказался от входа через One Tap, вызовите метод beginSignIn() объекта клиента и прикрепите прослушиватели к возвращаемому объекту Task. Обычно это делается в методе onCreate() класса Activity или после перехода между экранами, если используется архитектура с одним классом Activity.
- Сохраненные учетные данные найдены. Клиент One Tap вызовет прослушиватель успешного выполнения, если у пользователя есть сохраненные учетные данные для вашего приложения. В прослушивателе успешного выполнения получите отложенный интент из результата
Taskи передайте его вstartIntentSenderForResult(), чтобы запустить интерфейс входа через One Tap. Сохраненные учетные данные не найдены. Клиент One Tap вызовет прослушиватель сбоев. В этом случае никаких действий не требуется: вы можете продолжать предлагать пользователям функции приложения, доступные без входа в аккаунт. Однако если вы поддерживаете регистрацию через One Tap, то можете запустить этот процесс здесь, чтобы упростить создание аккаунта. Подробнее о том, как создавать аккаунты одним нажатием…
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. Обработка ответа пользователя
Ответ пользователя на предложение войти в аккаунт через One Tap будет передан в ваше приложение с помощью метода onActivityResult(). Если пользователь решил войти, результатом будут сохраненные учетные данные. Если пользователь отказался от входа, закрыв интерфейс One Tap или нажав за его пределами, будет возвращен результат с кодом RESULT_CANCELED. Ваше приложение должно поддерживать оба варианта.
Вход с полученными учетными данными
Если пользователь разрешил приложению доступ к учетным данным, вы можете получить их, передав данные intent из onActivityResult() в метод getSignInCredentialFromIntent() клиента One Tap. Если пользователь предоставил приложению доступ к учетным данным аккаунта Google, свойство googleIdToken будет иметь значение, отличное от null. Если пользователь предоставил доступ к сохраненному паролю, значение, отличное от null, будет иметь свойство password.
Используйте учетные данные для аутентификации в серверной части приложения.
- Если пара "имя пользователя – пароль" была получена, используйте ее для входа так же, как если бы пользователь ввел ее вручную.
Если учетные данные аккаунта Google были получены, используйте токен идентификатора для аутентификации в серверной части. Если вы решили использовать одноразовый код для защиты от атак повторного воспроизведения, проверьте значение ответа на бэкенд-сервере. Подробнее об аутентификации с помощью токенов идентификации…
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) {
// ...
}
}
}
}
// ...
}
Как отключить интерфейс One Tap
Если пользователь отказался от входа, вызов getSignInCredentialFromIntent() выдаст ApiException с кодом статуса CommonStatusCodes.CANCELED.
В этом случае вам следует временно отключить интерфейс входа через One Tap, чтобы не раздражать пользователей повторяющимися подсказками. В примере ниже это делается путем настройки свойства в Activity, которое используется для определения того, предлагать ли пользователю вход через One Tap. Однако вы также можете сохранить значение в SharedPreferences или использовать другой метод.
Важно реализовать собственное ограничение частоты запросов на вход через One Tap. Если вы этого не сделаете и пользователь отменит несколько подсказок подряд, клиент One Tap не будет запрашивать у пользователя следующие 24 часа.
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. Как обрабатывать выход из аккаунта
Когда пользователь выходит из приложения, вызовите метод signOut() клиента One Tap.
Вызов signOut() отключает автоматический вход, пока пользователь не войдет снова.
Даже если вы не используете автоматический вход, этот шаг важен, поскольку он гарантирует, что когда пользователи выходят из вашего приложения, состояние аутентификации всех используемых вами API сервисов Google Play также сбрасывается.
Дальнейшие действия
Если вы настроили клиент One Tap для получения учетных данных Google, ваше приложение теперь может получать токены идентификатора Google, которые представляют аккаунты Google ваших пользователей. Подробнее о том, как использовать эти токены на сервере…
Если вы поддерживаете вход с аккаунтом Google, то можете использовать клиент One Tap, чтобы добавить в приложение удобные способы создания аккаунта.