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

Предварительные требования
Убедитесь, что вы настроили привязку цифровых активов и что целевыми устройствами являются устройства под управлением Android 9 (уровень API 28) или выше.
Обзор
В этом руководстве рассматриваются изменения, необходимые в вашем клиентском приложении для зависимой стороны для создания пароля, и дается краткий обзор реализации серверной части приложения зависимой стороны . Для получения дополнительной информации об интеграции на стороне сервера см. раздел «Регистрация пароля на стороне сервера» .
- Добавьте зависимости в ваше приложение : добавьте необходимые библиотеки диспетчера учетных данных.
- Создание экземпляра диспетчера учетных данных : Создайте экземпляр диспетчера учетных данных.
- Получение параметров создания учетных данных с сервера приложений : с сервера приложений отправьте клиентскому приложению необходимые данные для создания пароля, такие как информация о приложении, пользователе, а также
challengeи другие поля. - Запрос пароля : В вашем приложении используйте данные, полученные с сервера приложений, для создания объекта
GetPublicKeyCredentialOptionи используйте этот объект для вызова методаcredentialManager.getCredential()для создания пароля. - Обработка ответа о создании ключа доступа : После получения учетных данных в клиентском приложении необходимо закодировать, сериализовать и отправить открытый ключ на сервер приложения. Также необходимо обработать все исключения, которые могут возникнуть в случае создания ключа доступа.
- Проверьте и сохраните открытый ключ на сервере : выполните действия на стороне сервера, чтобы проверить происхождение учетных данных, а затем сохраните открытый ключ.
- Уведомить пользователя : Уведомить пользователя о том, что его пароль создан.
Добавьте зависимости в ваше приложение.
Добавьте следующие зависимости в файл build.gradle вашего модуля приложения:
Котлин
dependencies { implementation("androidx.credentials:credentials:1.7.0-alpha02") implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha02") }
Круто
dependencies { implementation "androidx.credentials:credentials:1.7.0-alpha02" implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha02" }
Создать менеджер учетных данных
Используйте контекст вашего приложения или действия для создания объекта CredentialManager .
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
Получите параметры создания учетных данных с вашего сервера приложений.
Когда пользователь нажимает кнопку «Создать пароль» или когда регистрируется новый пользователь, ваше приложение отправляет запрос на сервер приложения для получения информации, необходимой для начала процесса регистрации пароля.
Используйте библиотеку, совместимую с FIDO, на сервере приложений, чтобы отправлять клиентскому приложению информацию, необходимую для создания пароля, такую как информация о пользователе, приложении и дополнительные параметры конфигурации. Для получения дополнительной информации см. раздел «Регистрация пароля на стороне сервера» .
В клиентском приложении необходимо декодировать параметры создания открытого ключа, отправленные сервером приложения. Обычно они представлены в формате JSON. Подробнее о том, как выполняется декодирование для веб-клиентов, см. в разделе «Кодирование и декодирование» . Для клиентских приложений Android декодирование необходимо обрабатывать отдельно.
Следующий фрагмент кода демонстрирует структуру параметров создания открытого ключа, отправляемых сервером приложений:
{
"challenge": "<base64url-encoded challenge>",
"rp": {
"name": "<relying party name>",
"id": "<relying party host name>"
},
"user": {
"id": "<base64url-encoded user ID>",
"name": "<user name>",
"displayName": "<user display name>"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
}
],
"attestation": "none",
"excludeCredentials": [
{
"id": "<base64url-encoded credential ID to exclude>",
"type": "public-key"
}
],
"authenticatorSelection": {
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
Ключевые поля в параметрах создания открытого ключа включают:
-
challenge: Сгенерированная сервером случайная строка, используемая для предотвращения атак повторного воспроизведения. -
rp: Подробная информация о приложении.-
rp.name: Название приложения. -
rp.id: Домен или поддомен приложения.
-
-
user: Подробная информация о пользователе.-
id: Уникальный идентификатор пользователя. Это значение не должно содержать личную информацию, например, адреса электронной почты или имена пользователей. Можно использовать случайное 16-байтовое значение. -
name: Уникальный идентификатор учетной записи, который пользователь сможет распознать, например, его адрес электронной почты или имя пользователя. Он будет отображаться в окне выбора учетной записи. При использовании имени пользователя используйте то же значение, что и при аутентификации по паролю. -
displayName: Необязательное, удобное для пользователя имя учетной записи, предназначенное для отображения в окне выбора учетной записи.
-
authenticatorSelection: Подробная информация об устройстве, которое будет использоваться для аутентификации.-
authenticatorAttachment: Указывает предпочтительный аутентификатор . Возможные значения: -platform: Это значение используется для аутентификатора, встроенного в устройство пользователя, например, датчика отпечатков пальцев. -cross-platform: Это значение используется для роуминговых устройств, таких как ключи безопасности. Обычно не используется в контексте пароля. - Unspecified (рекомендуется): Если оставить это значение неуказанным, это даст пользователям возможность создавать пароли на предпочитаемых ими устройствах. В большинстве случаев лучше оставить параметр неуказанным.-
requireResidentKey: Чтобы создать пароль, установите значение этогоBooleanполя вtrue. -
residentKey: Чтобы создать пароль, установите значениеrequired. -
userVerification: Используется для указания требований к проверке пользователя при регистрации пароля. Возможные значения: -preferred: Используйте это значение, если вы отдаете приоритет удобству использования, а не защите, например, в средах, где проверка пользователя создает больше неудобств, чем обеспечивает защиту. -required: Используйте это значение, если требуется использование метода проверки пользователя, доступного на устройстве. -discouraged: Используйте это значение, если использование метода проверки пользователя не рекомендуется.
Чтобы узнать больше оuserVerification, см. подробный анализ проверки пользователей (userVerification) .
-
-
excludeCredentials: Список идентификаторов учетных данных в виде массива , предотвращающий создание дубликата ключа доступа, если таковой уже существует у того же поставщика учетных данных.
Создать пароль
После того, как вы обработали параметры создания открытого ключа на стороне сервера, создайте пароль, обернув эти параметры в объект CreatePublicKeyCredentialRequest и вызвав createCredential() .
Метод createPublicKeyCredentialRequest включает в себя следующее:
-
requestJson: Параметры создания учетных данных, отправляемые сервером приложения. -
preferImmediatelyAvailableCredentials: Это необязательное логическое поле, определяющее, следует ли использовать для выполнения запроса только локально доступные или синхронизированные с поставщиком учетных данных учетные данные, вместо учетных данных из ключей безопасности или гибридных потоков ключей. Возможные варианты использования:-
false(по умолчанию): Используйте это значение, если вызов диспетчера учетных данных был инициирован явным действием пользователя. -
true: Используйте это значение, если диспетчер учетных данных вызывается автоматически, например, при первом запуске приложения.
Если установить значениеtrue, и нет доступных учетных данных, диспетчер учетных данных не отобразит никакого пользовательского интерфейса, и запрос немедленно завершится с ошибкой, возвращая NoCredentialException для запросов на получение иCreateCredentialNoCreateOptionExceptionдля запросов на создание.
-
-
origin: Это поле устанавливается автоматически для приложений Android. Для браузеров и аналогичных привилегированных приложений, которым необходимо установитьorigin, см. раздел «Выполнение вызовов диспетчера учетных данных от имени других сторон для привилегированных приложений» . -
isConditional: Это необязательное поле, значение по умолчанию —false. Дополнительную информацию см. в разделе «Автоматическое создание пароля» .
Вызов функции createCredential() запускает встроенный в Credential Manager интерфейс в нижней части экрана, который предлагает пользователю ввести пароль и выбрать поставщика учетных данных и учетную запись для хранения. Однако, если isConditional установлено в true , интерфейс в нижней части экрана не отображается, и пароль создается автоматически.
Автоматическое создание пароля
Вы можете автоматически создать пароль для пользователя после успешного входа по паролю, установив параметр isConditional в значение true в вашем запросе CreatePublicKeyCredentialRequest при создании пароля. Если у пользователя еще нет пароля, ваше приложение автоматически попытается создать его в фоновом режиме и сохранить в поставщике учетных данных пользователя, например, в Google Password Manager. Пример реализации см. в общедоступном примере .
Обработайте ответ
После подтверждения личности пользователя с помощью блокировки экрана устройства создается пароль, который сохраняется в выбранном пользователем поставщике учетных данных.
В ответ на успешный вызов метода createCredential() вы получите объект PublicKeyCredential .
Объект PublicKeyCredential выглядит следующим образом:
{
"id": "<identifier>",
"type": "public-key",
"rawId": "<identifier>",
"response": {
"clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
"attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
},
"authenticatorAttachment": "platform"
}
В клиентском приложении сериализуйте объект и отправьте его на сервер приложения.
Добавьте код для обработки ошибок, как показано в следующем фрагменте:
fun handleFailure(e: CreateCredentialException) {
when (e) {
is CreatePublicKeyCredentialDomException -> {
// Handle the passkey DOM errors thrown according to the
// WebAuthn spec.
}
is CreateCredentialCancellationException -> {
// The user intentionally canceled the operation and chose not
// to register the credential.
}
is CreateCredentialInterruptedException -> {
// Retry-able error. Consider retrying the call.
}
is CreateCredentialProviderConfigurationException -> {
// Your app is missing the provider configuration dependency.
// Most likely, you're missing the
// "credentials-play-services-auth" module.
}
is CreateCredentialCustomException -> {
// You have encountered an error from a 3rd-party SDK. If you
// make the API call with a request object that's a subclass of
// CreateCustomCredentialRequest using a 3rd-party SDK, then you
// should check for any custom exception type constants within
// that SDK to match with e.type. Otherwise, drop or log the
// exception.
}
else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}")
}
}
Проверьте и сохраните открытый ключ на сервере приложений.
На сервере приложений необходимо проверить учетные данные открытого ключа, а затем сохранить этот открытый ключ .
Для проверки происхождения учетных данных открытого ключа сравните их со списком разрешенных приложений. Если происхождение ключа неизвестно, отклоните его.
Чтобы получить отпечаток SHA 256 приложения:
Распечатайте сертификат подписи вашего релизного приложения, выполнив следующую команду в терминале:
keytool -list -keystore <path-to-apk-signing-keystore>В ответе необходимо определить отпечаток SHA 256 сертификата подписи, указанный как
Certificate fingerprints block:SHA256.Кодирование отпечатка SHA256 с помощью кодирования base64url. Этот пример на Python демонстрирует, как правильно закодировать отпечаток:
import binascii import base64 fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))Добавьте
android:apk-key-hash:` в начало выходных данных из предыдущего шага, чтобы получить что-то похожее на следующее:android:apk-key-hash:<encoded SHA 256 fingerprint>Результат должен совпадать с разрешенным источником на вашем сервере приложений. Если у вас несколько сертификатов подписи, например, сертификаты для отладки и выпуска, или несколько приложений, повторите процесс и примите все источники как действительные на сервере приложений.
Уведомить пользователя
После успешного создания пароля уведомите пользователей о нем и сообщите им, что они могут управлять своими паролями через приложение поставщика учетных данных или в настройках приложения . Уведомляйте пользователей с помощью пользовательского диалога, уведомления или всплывающей панели. Поскольку неожиданное создание пароля злоумышленником требует немедленного оповещения о безопасности, рассмотрите возможность дополнения этих внутриприложений внешними средствами связи, такими как электронная почта.
Улучшить пользовательский опыт
Для улучшения пользовательского опыта при регистрации с помощью Credential Manager рассмотрите возможность добавления функций восстановления учетных данных и отключения диалоговых окон автозаполнения.
Добавить функцию восстановления учетных данных на новом устройстве.
Чтобы пользователи могли беспрепятственно входить в свои учетные записи на новом устройстве, реализуйте функцию восстановления учетных данных . Добавление учетных данных для восстановления с помощью BackupAgent позволяет пользователям входить в систему при открытии восстановленного приложения на новом устройстве, что дает им возможность сразу же начать им пользоваться.
Отключить автозаполнение полей учетных данных (необязательно)
Для экранов приложения, где предполагается, что пользователи будут использовать нижний экранный интерфейс диспетчера учетных данных для аутентификации, добавьте атрибут isCredential к полям имени пользователя и пароля. Это предотвратит перекрытие диалоговых окон автозаполнения ( FillDialog и SaveDialog ) с нижним экранным интерфейсом диспетчера учетных данных.
Атрибут isCredential поддерживается в Android 14 и более поздних версиях.
В следующем примере показано, как добавить атрибут isCredential к соответствующим полям имени пользователя и пароля в соответствующих представлениях вашего приложения:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true" />
Следующие шаги
- Вход с помощью паролей
- Управление ключами доступа
- Понимание сценариев взаимодействия пользователя с ключом доступа