Войти с помощью пароля

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

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

Обзор

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

Чтобы получить доступ ко всем параметрам пароля и ключам доступа, связанным с учетной записью пользователя, выполните следующие действия:

  1. Получение параметров запроса учетных данных с сервера : отправьте запрос из вашего приложения на сервер аутентификации, чтобы начать процесс входа в систему с помощью пароля. С сервера отправьте параметры, необходимые для получения учетных данных открытого ключа, а также уникальный запрос.
  2. Создайте объект, необходимый для получения учетных данных открытого ключа : оберните параметры, отправленные сервером, в объект GetPublicKeyCredentialOption
  3. ( необязательно) Подготовка метода getCredential : В Android 14 и выше можно уменьшить задержку, отобразив селектор учетной записи с помощью метода prepareGetCredential() перед вызовом метода getCredential() .
  4. Запуск процесса авторизации : вызовите метод getCredential() для авторизации пользователя.
  5. Обработка ответа : обработайте каждый из возможных ответов, содержащих учетные данные.
  6. Обработка исключений : Убедитесь, что вы надлежащим образом обрабатываете исключения.

Получите параметры запроса учетных данных с сервера.

Запросите у сервера параметры, необходимые для получения учетных данных открытого ключа, а также challenge , который уникален для каждой попытки входа в систему. Подробнее о реализации на стороне сервера см. в разделах «Создание запроса на ввод данных» и «Создание параметров запроса учетных данных» .

Варианты выглядят примерно так:

{
  "challenge": "<your app challenge>",
  "allowCredentials": [],
  "rpId": "<your app server domain>"
}

Чтобы узнать больше об этих полях, ознакомьтесь с записью в блоге о входе в систему с помощью пароля .

Создайте объект, необходимый для получения учетных данных открытого ключа.

В вашем приложении используйте параметры для создания объекта GetPublicKeyCredentialOption . В следующем примере requestJson представляет параметры, отправленные сервером.

// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()

// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
    requestJson = requestJson
)

Затем оберните GetPublicKeyCredentialOption в объект GetCredentialRequest .

val credentialRequest = GetCredentialRequest(
    // Include all the sign-in options that your app supports.
    listOf(getPasswordOption, getPublicKeyCredentialOption),
    // Defines whether you prefer to use only immediately available
    // credentials or hybrid credentials.
    preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)

Дополнительно: Уменьшить задержку при входе в систему.

На Android 14 и более поздних версиях можно уменьшить задержку при отображении выбора учетной записи, используя метод prepareGetCredential() перед вызовом getCredential() .

Метод prepareGetCredential() возвращает объект PrepareGetCredentialResponse , который кэшируется. Это позволяет методу getCredential() на следующем шаге отобразить селектор учетных записей с кэшированными данными.

coroutineScope {
    val response = credentialManager.prepareGetCredential(
        GetCredentialRequest(
            listOf(
                // Include all the sign-in options that your app supports
                getPublicKeyCredentialOption, 
                getPasswordOption
            )
        )
    )
}

Запустите процесс авторизации.

Вызовите метод getCredential() , чтобы показать пользователю окно выбора учетной записи. Используйте следующий фрагмент кода в качестве примера запуска процесса входа в систему:

// Use an activity-based context to avoid undefined system UI
// launching behavior.
val context = MutableContextWrapper(activityContext)
coroutineScope {
    try {
        result = credentialManager.getCredential(
            // Use MutableContextWrapper to avoid memory leak during configuration changes
            context = context,
            request = credentialRequest
        )
        handleSignIn(result)
    } catch (e: GetCredentialException) {
        // Handle failure
    }
}

Обработайте ответ

Обработайте ответ, который может содержать один из различных типов объектов учетных данных.

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

    when (credential) {
        is PublicKeyCredential -> {
            val responseJson = credential.authenticationResponseJson
            // Share responseJson i.e. a GetCredentialResponse on your server to
            // validate and  authenticate
        }

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

        is CustomCredential -> {
            // If you are also using any external sign-in libraries, parse them
            // here with the utility functions provided.
            if (credential.type == ExampleCustomCredential.TYPE) {
                try {
                    val ExampleCustomCredential =
                        ExampleCustomCredential.createFrom(credential.data)
                    // Extract the required credentials and complete the authentication as per
                    // the federated sign in or any external sign in library flow
                } catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
                    // Unlikely to happen. If it does, you likely need to update the dependency
                    // version of your external sign-in library.
                    Log.e(TAG, "Failed to parse an ExampleCustomCredential", 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")
        }
    }
}

Объект PublicKeyCredential , возвращаемый в результате аутентификации, по сути представляет собой подписанное утверждение, имеющее следующую структуру:

{
  "id": "<credential ID>",
  "type": "public-key",
  "rawId": "<raw credential ID>",
  "response": {
    "clientDataJSON": "<signed client data containing challenge>",
    "authenticatorData": "<authenticator metadata>",
    "signature": "<digital signature to be verified>",
    "userHandle": "<user ID from credential registration>"
  }
}

На сервере необходимо проверить учетные данные. Для получения дополнительной информации см. раздел «Проверка и вход пользователя» .

Обработка исключений

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

coroutineScope {
    try {
        result = credentialManager.getCredential(
            context = activityContext,
            request = credentialRequest
        )
    } catch (e: GetCredentialException) {
        Log.e("CredentialManager", "No credential available", e)
    }
}

Следующие шаги