Аутентификация пользователей с помощью «Войти через Google»

Вход с помощью Google поможет вам быстро интегрировать аутентификацию пользователей с вашим приложением Android. Пользователи могут использовать свою учетную запись Google для входа в ваше приложение, предоставления согласия и безопасного обмена информацией своего профиля с вашим приложением. Библиотека Android Credential Manager Jetpack упрощает эту интеграцию, предлагая единообразную работу на всех устройствах Android с использованием единого API.

В этом документе рассказывается, как реализовать функцию «Вход с помощью Google» в приложениях Android, как настроить пользовательский интерфейс кнопки «Вход с помощью Google», а также настроить оптимизированную для приложений процедуру регистрации и входа в систему одним касанием. Для плавной миграции устройств функция «Вход с Google» поддерживает автоматический вход, а ее кросс-платформенный характер для Android, iOS и веб-интерфейсов помогает вам предоставить доступ для входа в приложение на любом устройстве.

Чтобы настроить вход через Google, выполните следующие два основных шага:

Настройте «Вход с помощью Google» в качестве опции для пользовательского интерфейса нижнего листа диспетчера учетных данных . Это можно настроить так, чтобы пользователю автоматически предлагалось войти в систему. Если вы внедрили ключи доступа или пароли , вы можете запрашивать все соответствующие типы учетных данных одновременно, чтобы пользователю не приходилось запоминать вариант, который он использовал ранее для входа в систему. .

Нижний лист диспетчера учетных данных
Рисунок 1. Пользовательский интерфейс выбора учетных данных нижнего листа Credential Manager.

Добавьте кнопку «Войти через Google» в пользовательский интерфейс вашего приложения . Кнопка «Войти через Google» предлагает пользователям упрощенный способ использования существующих учетных записей Google для регистрации или входа в приложения Android. Пользователи нажмут кнопку «Войти через Google», если они закроют пользовательский интерфейс нижнего листа или если они явно захотят использовать свою учетную запись Google для регистрации и входа в систему. Для разработчиков это означает упрощение регистрации пользователей и снижение сложностей во время регистрации.

Анимация, показывающая процесс входа в систему с помощью Google.
Рис. 2. Пользовательский интерфейс кнопки «Войти с помощью Google» в диспетчере учетных данных.

В этом документе объясняется, как интегрировать кнопку «Войти с помощью Google» и диалоговое окно нижнего листа с API диспетчера учетных данных с помощью вспомогательной библиотеки идентификаторов Google .

Настройте консольный проект Google API

  1. Откройте свой проект в консоли API или создайте проект, если у вас его еще нет.
  2. На странице экрана согласия OAuth убедитесь, что вся информация полная и точная.
    1. Убедитесь, что вашему приложению назначены правильное имя, логотип и домашняя страница приложения. Эти значения будут представлены пользователям на экране согласия «Вход с помощью Google» при регистрации и на экране «Сторонние приложения и службы» .
    2. Убедитесь, что вы указали URL-адреса политики конфиденциальности и условий обслуживания вашего приложения.
  3. На странице «Учетные данные» создайте идентификатор клиента Android для своего приложения, если у вас его еще нет. Вам нужно будет указать имя пакета вашего приложения и подпись SHA-1.
    1. Перейдите на страницу учетных данных .
    2. Нажмите Создать учетные данные > Идентификатор клиента OAuth .
    3. Выберите тип приложения Android .
  4. На странице «Учетные данные» создайте новый идентификатор клиента «Веб-приложение», если вы еще этого не сделали. На данный момент вы можете игнорировать поля «Авторизованные источники JavaScript» и «Авторизованные URI перенаправления». Этот идентификатор клиента будет использоваться для идентификации вашего внутреннего сервера, когда он взаимодействует со службами аутентификации Google.
    1. Перейдите на страницу учетных данных .
    2. Нажмите Создать учетные данные > Идентификатор клиента OAuth .
    3. Выберите тип веб-приложения.

Объявить зависимости

В файле build.gradle вашего модуля объявите зависимости, используя последнюю версию Credential Manager :

dependencies {
  // ... other dependencies

  implementation "androidx.credentials:credentials:<latest version>"
  implementation "androidx.credentials:credentials-play-services-auth:<latest version>"
  implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}

Создание экземпляра запроса на вход в Google

Чтобы начать реализацию, создайте экземпляр запроса на вход в Google . Используйте GetGoogleIdOption , чтобы получить токен идентификатора Google пользователя.

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Сначала проверьте, есть ли у пользователя какие-либо учетные записи, которые ранее использовались для входа в ваше приложение, вызвав API с параметром setFilterByAuthorizedAccounts , для которого установлено значение true . Пользователи могут выбирать между доступными учетными записями для входа.

Если авторизованных учетных записей Google нет, пользователю будет предложено зарегистрироваться с использованием любой из доступных учетных записей. Для этого предложите пользователю еще раз вызвать API и установить для setFilterByAuthorizedAccounts значение false . Узнайте больше о регистрации .

Включить автоматический вход для вернувшихся пользователей (рекомендуется)

Разработчикам следует включить автоматический вход для пользователей, которые регистрируются под одной учетной записью. Это обеспечивает бесперебойную работу на всех устройствах, особенно во время миграции устройств, когда пользователи могут быстро восстановить доступ к своей учетной записи без повторного ввода учетных данных. Для ваших пользователей это устраняет ненужные трудности, когда они уже ранее вошли в систему.

Чтобы включить автоматический вход, используйте setAutoSelectEnabled(true) . Автоматический вход возможен только при соблюдении следующих критериев:

  • Запросу соответствуют единые учетные данные, которые могут быть учетной записью Google или паролем, и эти учетные данные соответствуют учетной записи по умолчанию на устройстве под управлением Android.
  • Пользователь не вышел из системы явным образом.
  • Пользователь не отключил автоматический вход в настройках своего аккаунта Google .
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Не забудьте правильно обработать выход при реализации автоматического входа, чтобы пользователи всегда могли выбрать правильную учетную запись после явного выхода из вашего приложения.

Установите nonce для повышения безопасности

Чтобы повысить безопасность входа в систему и избежать атак повторного воспроизведения, добавьте setNonce , чтобы включать одноразовый номер в каждый запрос. Узнайте больше о создании nonce .

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(WEB_CLIENT_ID)
  .setAutoSelectEnabled(true)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Создайте процесс входа в систему с помощью Google

Шаги по настройке процесса входа в систему с помощью Google следующие:

  1. Создайте экземпляр GetCredentialRequest , затем добавьте ранее созданный googleIdOption с помощью addCredentialOption() для получения учетных данных.
  2. Передайте этот запрос вызову getCredential() (Kotlin) или getCredentialAsync() (Java), чтобы получить доступные учетные данные пользователя.
  3. После успешного выполнения API извлеките CustomCredential , который содержит результат для данных GoogleIdTokenCredential .
  4. Тип CustomCredential должен быть равен значению GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL . Преобразуйте объект в GoogleIdTokenCredential с помощью метода GoogleIdTokenCredential.createFrom .
  5. Если преобразование прошло успешно, извлеките идентификатор GoogleIdTokenCredential , проверьте его и подтвердите подлинность учетных данных на своем сервере.

  6. Если преобразование завершается неудачно с исключением GoogleIdTokenParsingException , вам может потребоваться обновить версию библиотеки для входа в систему Google .

  7. Перехватите любые нераспознанные типы пользовательских учетных данных.

val request: GetCredentialRequest = Builder()
  .addCredentialOption(googleIdOption)
  .build()

coroutineScope.launch {
  try {
    val result = credentialManager.getCredential(
      request = request,
      context = activityContext,
    )
    handleSignIn(result)
  } catch (e: GetCredentialException) {
    handleFailure(e)
  }
}

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {

    // Passkey credential
    is PublicKeyCredential -> {
      // Share responseJson such as a GetCredentialResponse on your server to
      // validate and authenticate
      responseJson = credential.authenticationResponseJson
    }

    // Password credential
    is PasswordCredential -> {
      // Send ID and password to your server to validate and authenticate.
      val username = credential.id
      val password = credential.password
    }

    // GoogleIdToken credential
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract the ID to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
          // You can use the members of googleIdTokenCredential directly for UX
          // purposes, but don't use them to store or control access to user
          // data. For that you first need to validate the token:
          // pass googleIdTokenCredential.getIdToken() to the backend server.
          GoogleIdTokenVerifier verifier = ... // see validation instructions
          GoogleIdToken idToken = verifier.verify(idTokenString);
          // To get a stable account identifier (e.g. for storing user data),
          // use the subject ID:
          idToken.getPayload().getSubject()
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      } else {
        // Catch any unrecognized custom credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

Запуск кнопки «Войти с помощью Google»

Чтобы активировать поток кнопки «Войти с помощью Google», используйте GetSignInWithGoogleOption вместо GetGoogleIdOption :

val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder()
  .setServerClientId(WEB_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Обработайте возвращенный GoogleIdTokenCredential , как описано в следующем примере кода.

fun handleSignIn(result: GetCredentialResponse) {
  // Handle the successfully returned credential.
  val credential = result.credential

  when (credential) {
    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract id to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      }
      else -> {
        // Catch any unrecognized credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

    else -> {
      // Catch any unrecognized credential type here.
      Log.e(TAG, "Unexpected type of credential")
    }
  }
}

После создания экземпляра запроса на вход в Google запустите процесс аутентификации аналогично тому, как указано в разделе «Вход с помощью Google» .

Включить регистрацию для новых пользователей (рекомендуется)

Вход с помощью Google — это самый простой способ для пользователей создать новую учетную запись в вашем приложении или сервисе всего за несколько нажатий.

Если сохраненные учетные данные не найдены (учетные записи Google не возвращаются методом getGoogleIdOption ), предложите пользователю зарегистрироваться. Сначала проверьте, установлен ли setFilterByAuthorizedAccounts(true) чтобы узнать, существуют ли какие-либо ранее использованные учетные записи. Если ничего не найдено, предложите пользователю зарегистрироваться под своей учетной записью Google, используя setFilterByAuthorizedAccounts(false)

Пример:

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(false)
  .setServerClientId(WEB_CLIENT_ID)
  .build()

После создания экземпляра запроса на регистрацию в Google запустите процесс аутентификации. Если пользователи не хотят использовать «Вход через Google» для регистрации, рассмотрите возможность оптимизации вашего приложения для автозаполнения . После того как ваш пользователь создал учетную запись, рассмотрите возможность регистрации его в качестве ключей доступа в качестве последнего шага к созданию учетной записи.

Обработка выхода из системы

Когда пользователь выходит из вашего приложения, вызовите метод API clearCredentialState() чтобы очистить текущее состояние учетных данных пользователя от всех поставщиков учетных данных. Это уведомит всех поставщиков учетных данных о том, что любой сохраненный сеанс учетных данных для данного приложения должен быть очищен.

Поставщик учетных данных может сохранить активный сеанс учетных данных и использовать его для ограничения возможностей входа в систему для будущих вызовов получения учетных данных. Например, он может установить приоритет активных учетных данных над любыми другими доступными учетными данными. Когда ваш пользователь явно выходит из вашего приложения и чтобы в следующий раз получить целостные параметры входа, вам следует вызвать этот API, чтобы позволить поставщику очистить любой сохраненный сеанс учетных данных.