Благодаря поддержке ключей доступа , федеративного входа и сторонних поставщиков аутентификации Credential Manager является рекомендуемым API для аутентификации на Android, который обеспечивает безопасную и удобную среду, позволяющую пользователям синхронизировать свои учетные данные и управлять ими. Разработчикам, использующим локальные учетные данные FIDO2 , следует обновить приложение, чтобы оно поддерживало проверку подлинности с помощью пароля путем интеграции с API диспетчера учетных данных. В этом документе описывается, как перенести проект из FIDO2 в Credential Manager.
Причины перехода с FIDO2 на Credential Manager
В большинстве случаев вам следует перенести поставщика аутентификации вашего приложения Android в Credential Manager. Причины перехода на Credential Manager включают в себя:
- Поддержка ключей доступа: Credential Manager поддерживает ключи доступа — новый механизм аутентификации без пароля, который более безопасен и прост в использовании, чем пароли.
- Несколько методов входа. Диспетчер учетных данных поддерживает несколько методов входа, включая пароли, ключи доступа и методы федеративного входа. Это упрощает аутентификацию пользователей в вашем приложении независимо от предпочтительного метода аутентификации.
- Поддержка сторонних поставщиков учетных данных. В Android 14 и более поздних версиях Credential Manager поддерживает несколько сторонних поставщиков учетных данных. Это означает, что ваши пользователи могут использовать свои существующие учетные данные от других поставщиков для входа в ваше приложение.
- Единообразный пользовательский интерфейс. Credential Manager обеспечивает более единообразный пользовательский интерфейс для аутентификации в приложениях и механизмах входа. Это облегчает пользователям понимание и использование процесса аутентификации вашего приложения.
Чтобы начать миграцию с FIDO2 на Credential Manager, выполните следующие действия.
Обновить зависимости
Обновите плагин Kotlin в build.gradle вашего проекта до версии 1.8.10 или выше.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
В build.gradle вашего проекта обновите зависимости, чтобы использовать диспетчер учетных данных и проверку подлинности служб Play.
dependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
Замените инициализацию FIDO инициализацией диспетчера учетных данных. Добавьте это объявление в класс, который вы используете для создания ключа доступа и методов входа:
val credMan = CredentialManager.create(context)
Создать ключи доступа
Вам потребуется создать новый ключ доступа, связать его с учетной записью пользователя и сохранить открытый ключ ключа доступа на своем сервере, прежде чем пользователь сможет войти с ним в систему. Настройте свое приложение с этой возможностью, обновив вызовы функций регистрации.
Чтобы получить необходимые параметры, которые отправляются в метод
createCredential()
во время создания ключа доступа, добавьтеname("residentKey").value("required")
как описано в спецификации WebAuthn ) к серверному вызовуregisterRequest()
.suspend fun registerRequest(sessionId: String ... { // ... .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() // ... }
Установите тип
return
дляregisterRequest()
и всех дочерних функций наJSONObject
.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Request.Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } }).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средства запуска намерений и вызовы результатов действий.
Поскольку
registerRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
. Обновите вызовы средства запуска намерений, чтобы они вызывалиcreateCredential()
из API диспетчера учетных данных. Вызовите метод APIcreateCredential()
.suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request as CreateCredentialRequest, activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
После успешного вызова отправьте ответ обратно на сервер. Запрос и ответ на этот вызов аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Аутентификация с помощью ключей доступа
После настройки создания ключей доступа вы можете настроить свое приложение так, чтобы пользователи могли входить в систему и проходить аутентификацию с использованием своих ключей доступа. Для этого вы обновите свой код аутентификации для обработки результатов диспетчера учетных данных и реализуете функцию для аутентификации с помощью ключей доступа.
- Ваш вызов запроса на вход на сервер для получения необходимой информации для отправки в запрос
getCredential()
аналогичен реализации FIDO2. Никаких изменений не требуется. Подобно вызову запроса на регистрацию, возвращаемый ответ имеет формат JSONObject.
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall(Builder().url(buildString { append("$BASE_URL/signinRequest") }).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie",formatCookie(sessionId)) .method("POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } }).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средство запуска намерений и вызовы результатов активности.
Поскольку
signInRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
и вызовитеgetCredential()
из методов API.suspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT) .show() var result: GetCredentialResponse? = null try { val request= GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }
После успешного вызова отправьте ответ обратно на сервер для проверки и аутентификации пользователя. Параметры запроса и ответа для этого вызова API аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Дополнительные ресурсы
- Образец справочника по диспетчеру учетных данных
- Менеджер учетных данных Codelab
- Обеспечение простой аутентификации в ваших приложениях с помощью ключей доступа с помощью API Credential Manager.
- Лаборатория кода FIDO2
Благодаря поддержке ключей доступа , федеративного входа и сторонних поставщиков аутентификации Credential Manager является рекомендуемым API для аутентификации на Android, который обеспечивает безопасную и удобную среду, позволяющую пользователям синхронизировать свои учетные данные и управлять ими. Разработчикам, использующим локальные учетные данные FIDO2 , следует обновить приложение, чтобы оно поддерживало проверку подлинности с помощью пароля путем интеграции с API диспетчера учетных данных. В этом документе описывается, как перенести проект из FIDO2 в Credential Manager.
Причины перехода с FIDO2 на Credential Manager
В большинстве случаев вам следует перенести поставщика аутентификации вашего приложения Android в Credential Manager. Причины перехода на Credential Manager включают в себя:
- Поддержка ключей доступа: Credential Manager поддерживает ключи доступа — новый механизм аутентификации без пароля, который более безопасен и прост в использовании, чем пароли.
- Несколько методов входа. Диспетчер учетных данных поддерживает несколько методов входа, включая пароли, ключи доступа и методы федеративного входа. Это упрощает аутентификацию пользователей в вашем приложении независимо от предпочтительного метода аутентификации.
- Поддержка сторонних поставщиков учетных данных. В Android 14 и более поздних версиях Credential Manager поддерживает несколько сторонних поставщиков учетных данных. Это означает, что ваши пользователи могут использовать свои существующие учетные данные от других поставщиков для входа в ваше приложение.
- Единообразный пользовательский интерфейс. Credential Manager обеспечивает более единообразный пользовательский интерфейс для аутентификации в приложениях и механизмах входа. Это облегчает пользователям понимание и использование процесса аутентификации вашего приложения.
Чтобы начать миграцию с FIDO2 на Credential Manager, выполните следующие действия.
Обновить зависимости
Обновите плагин Kotlin в build.gradle вашего проекта до версии 1.8.10 или выше.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
В build.gradle вашего проекта обновите зависимости, чтобы использовать диспетчер учетных данных и проверку подлинности служб Play.
dependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
Замените инициализацию FIDO инициализацией диспетчера учетных данных. Добавьте это объявление в класс, который вы используете для создания ключа доступа и методов входа:
val credMan = CredentialManager.create(context)
Создать ключи доступа
Вам потребуется создать новый ключ доступа, связать его с учетной записью пользователя и сохранить открытый ключ ключа доступа на своем сервере, прежде чем пользователь сможет войти с ним в систему. Настройте свое приложение с этой возможностью, обновив вызовы функций регистрации.
Чтобы получить необходимые параметры, которые отправляются в метод
createCredential()
во время создания ключа доступа, добавьтеname("residentKey").value("required")
как описано в спецификации WebAuthn ) к серверному вызовуregisterRequest()
.suspend fun registerRequest(sessionId: String ... { // ... .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() // ... }
Установите тип
return
дляregisterRequest()
и всех дочерних функций наJSONObject
.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Request.Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } }).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средства запуска намерений и вызовы результатов действий.
Поскольку
registerRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
. Обновите вызовы средства запуска намерений, чтобы они вызывалиcreateCredential()
из API диспетчера учетных данных. Вызовите метод APIcreateCredential()
.suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request as CreateCredentialRequest, activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
После успешного вызова отправьте ответ обратно на сервер. Запрос и ответ на этот вызов аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Аутентификация с помощью ключей доступа
После настройки создания ключей доступа вы можете настроить свое приложение так, чтобы пользователи могли входить в систему и проходить аутентификацию с использованием своих ключей доступа. Для этого вы обновите свой код аутентификации для обработки результатов диспетчера учетных данных и реализуете функцию для аутентификации с помощью ключей доступа.
- Ваш вызов запроса на вход на сервер для получения необходимой информации для отправки в запрос
getCredential()
аналогичен реализации FIDO2. Никаких изменений не требуется. Подобно вызову запроса на регистрацию, возвращаемый ответ имеет формат JSONObject.
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall(Builder().url(buildString { append("$BASE_URL/signinRequest") }).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie",formatCookie(sessionId)) .method("POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } }).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средство запуска намерений и вызовы результатов активности.
Поскольку
signInRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
и вызовитеgetCredential()
из методов API.suspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT) .show() var result: GetCredentialResponse? = null try { val request= GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }
После успешного вызова отправьте ответ обратно на сервер для проверки и аутентификации пользователя. Параметры запроса и ответа для этого вызова API аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Дополнительные ресурсы
- Образец справочника по диспетчеру учетных данных
- Менеджер учетных данных Codelab
- Обеспечение простой аутентификации в ваших приложениях с помощью ключей доступа с помощью API Credential Manager.
- Лаборатория кода FIDO2
Благодаря поддержке ключей доступа , федеративного входа и сторонних поставщиков аутентификации Credential Manager является рекомендуемым API для аутентификации на Android, который обеспечивает безопасную и удобную среду, позволяющую пользователям синхронизировать свои учетные данные и управлять ими. Разработчикам, использующим локальные учетные данные FIDO2 , следует обновить приложение, чтобы оно поддерживало проверку подлинности с помощью пароля путем интеграции с API диспетчера учетных данных. В этом документе описывается, как перенести проект из FIDO2 в Credential Manager.
Причины перехода с FIDO2 на Credential Manager
В большинстве случаев вам следует перенести поставщика аутентификации вашего приложения Android в Credential Manager. Причины перехода на Credential Manager включают в себя:
- Поддержка ключей доступа: Credential Manager поддерживает ключи доступа — новый механизм аутентификации без пароля, который более безопасен и прост в использовании, чем пароли.
- Несколько методов входа. Диспетчер учетных данных поддерживает несколько методов входа, включая пароли, ключи доступа и методы федеративного входа. Это упрощает аутентификацию пользователей в вашем приложении независимо от предпочтительного метода аутентификации.
- Поддержка сторонних поставщиков учетных данных. В Android 14 и более поздних версиях Credential Manager поддерживает несколько сторонних поставщиков учетных данных. Это означает, что ваши пользователи могут использовать свои существующие учетные данные от других поставщиков для входа в ваше приложение.
- Единообразный пользовательский интерфейс. Credential Manager обеспечивает более единообразный пользовательский интерфейс для аутентификации в приложениях и механизмах входа. Это облегчает пользователям понимание и использование процесса аутентификации вашего приложения.
Чтобы начать миграцию с FIDO2 на Credential Manager, выполните следующие действия.
Обновить зависимости
Обновите плагин Kotlin в build.gradle вашего проекта до версии 1.8.10 или выше.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
В build.gradle вашего проекта обновите зависимости, чтобы использовать диспетчер учетных данных и проверку подлинности служб Play.
dependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
Замените инициализацию FIDO инициализацией диспетчера учетных данных. Добавьте это объявление в класс, который вы используете для создания ключа доступа и методов входа:
val credMan = CredentialManager.create(context)
Создать ключи доступа
Вам нужно будет создать новый ключ доступа, связать его с учетной записью пользователя и сохранить открытый ключ ключа доступа на своем сервере, прежде чем пользователь сможет войти с ним в систему. Настройте свое приложение с этой возможностью, обновив вызовы функций регистрации.
Чтобы получить необходимые параметры, которые отправляются в метод
createCredential()
во время создания ключа доступа, добавьтеname("residentKey").value("required")
как описано в спецификации WebAuthn ) к серверному вызовуregisterRequest()
.suspend fun registerRequest(sessionId: String ... { // ... .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() // ... }
Установите тип
return
дляregisterRequest()
и всех дочерних функций наJSONObject
.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Request.Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } }).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средства запуска намерений и вызовы результатов действий.
Поскольку
registerRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
. Обновите вызовы средства запуска намерений, чтобы они вызывалиcreateCredential()
из API диспетчера учетных данных. Вызовите метод APIcreateCredential()
.suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request as CreateCredentialRequest, activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
После успешного вызова отправьте ответ обратно на сервер. Запрос и ответ на этот вызов аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Аутентификация с помощью ключей доступа
После настройки создания ключей доступа вы можете настроить свое приложение так, чтобы пользователи могли входить в систему и проходить аутентификацию с использованием своих ключей доступа. Для этого вы обновите свой код аутентификации для обработки результатов диспетчера учетных данных и реализуете функцию аутентификации с помощью ключей доступа.
- Ваш вызов запроса на вход на сервер для получения необходимой информации для отправки в запрос
getCredential()
аналогичен реализации FIDO2. Никаких изменений не требуется. Подобно вызову запроса на регистрацию, возвращаемый ответ имеет формат JSONObject.
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall(Builder().url(buildString { append("$BASE_URL/signinRequest") }).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie",formatCookie(sessionId)) .method("POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } }).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средство запуска намерений и вызовы результатов действий.
Поскольку
signInRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
и вызовитеgetCredential()
из методов API.suspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT) .show() var result: GetCredentialResponse? = null try { val request= GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }
После успешного вызова отправьте ответ обратно на сервер для проверки и аутентификации пользователя. Параметры запроса и ответа для этого вызова API аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Дополнительные ресурсы
- Образец справочника по диспетчеру учетных данных
- Менеджер учетных данных Codelab
- Обеспечение простой аутентификации в ваших приложениях с помощью ключей доступа с помощью API Credential Manager.
- Лаборатория кода FIDO2
Благодаря поддержке ключей доступа , федеративного входа и сторонних поставщиков аутентификации Credential Manager является рекомендуемым API для аутентификации на Android, который обеспечивает безопасную и удобную среду, позволяющую пользователям синхронизировать свои учетные данные и управлять ими. Разработчикам, использующим локальные учетные данные FIDO2 , следует обновить приложение, чтобы оно поддерживало проверку подлинности с помощью пароля путем интеграции с API диспетчера учетных данных. В этом документе описывается, как перенести проект из FIDO2 в Credential Manager.
Причины перехода с FIDO2 на Credential Manager
В большинстве случаев вам следует перенести поставщика аутентификации вашего приложения Android в Credential Manager. Причины перехода на Credential Manager включают в себя:
- Поддержка ключей доступа: Credential Manager поддерживает ключи доступа — новый механизм аутентификации без пароля, который более безопасен и прост в использовании, чем пароли.
- Несколько методов входа. Диспетчер учетных данных поддерживает несколько методов входа, включая пароли, ключи доступа и методы федеративного входа. Это упрощает аутентификацию пользователей в вашем приложении независимо от предпочтительного метода аутентификации.
- Поддержка сторонних поставщиков учетных данных. В Android 14 и более поздних версиях Credential Manager поддерживает несколько сторонних поставщиков учетных данных. Это означает, что ваши пользователи могут использовать свои существующие учетные данные от других поставщиков для входа в ваше приложение.
- Единообразный пользовательский интерфейс. Credential Manager обеспечивает более единообразный пользовательский интерфейс для аутентификации в приложениях и механизмах входа. Это облегчает пользователям понимание и использование процесса аутентификации вашего приложения.
Чтобы начать миграцию с FIDO2 на Credential Manager, выполните следующие действия.
Обновить зависимости
Обновите плагин Kotlin в build.gradle вашего проекта до версии 1.8.10 или выше.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
В build.gradle вашего проекта обновите зависимости, чтобы использовать диспетчер учетных данных и проверку подлинности служб Play.
dependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
Замените инициализацию FIDO инициализацией диспетчера учетных данных. Добавьте это объявление в класс, который вы используете для создания ключа доступа и методов входа:
val credMan = CredentialManager.create(context)
Создать ключи доступа
Вам нужно будет создать новый ключ доступа, связать его с учетной записью пользователя и сохранить открытый ключ ключа доступа на своем сервере, прежде чем пользователь сможет войти с ним в систему. Настройте свое приложение с этой возможностью, обновив вызовы функций регистрации.
Чтобы получить необходимые параметры, которые отправляются в метод
createCredential()
во время создания ключа доступа, добавьтеname("residentKey").value("required")
как описано в спецификации WebAuthn ) к серверному вызовуregisterRequest()
.suspend fun registerRequest(sessionId: String ... { // ... .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() // ... }
Установите тип
return
дляregisterRequest()
и всех дочерних функций наJSONObject
.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Request.Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } }).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средства запуска намерений и вызовы результатов действий.
Поскольку
registerRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
. Обновите вызовы средства запуска намерений, чтобы они вызывалиcreateCredential()
из API диспетчера учетных данных. Вызовите метод APIcreateCredential()
.suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request as CreateCredentialRequest, activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
После успешного вызова отправьте ответ обратно на сервер. Запрос и ответ на этот вызов аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Аутентификация с помощью ключей доступа
После настройки создания ключей доступа вы можете настроить свое приложение так, чтобы пользователи могли входить в систему и проходить аутентификацию с использованием своих ключей доступа. Для этого вы обновите свой код аутентификации для обработки результатов диспетчера учетных данных и реализуете функцию для аутентификации с помощью ключей доступа.
- Ваш вызов запроса на вход на сервер для получения необходимой информации для отправки в запрос
getCredential()
аналогичен реализации FIDO2. Никаких изменений не требуется. Подобно вызову запроса на регистрацию, возвращаемый ответ имеет формат JSONObject.
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall(Builder().url(buildString { append("$BASE_URL/signinRequest") }).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie",formatCookie(sessionId)) .method("POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } }).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }
Безопасно удалите из поля зрения все методы, которые обрабатывают средство запуска намерений и вызовы результатов активности.
Поскольку
signInRequest()
теперь возвращаетJSONObject
, вам не нужно создаватьPendingIntent
. Замените возвращенное намерение наJSONObject
и вызовитеgetCredential()
из методов API.suspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT) .show() var result: GetCredentialResponse? = null try { val request= GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }
После успешного вызова отправьте ответ обратно на сервер для проверки и аутентификации пользователя. Параметры запроса и ответа для этого вызова API аналогичны реализации FIDO2, поэтому никаких изменений не требуется.
Дополнительные ресурсы
- Образец справочника по диспетчеру учетных данных
- Менеджер учетных данных Codelab
- Обеспечение простой аутентификации в ваших приложениях с помощью ключей доступа с помощью API Credential Manager.
- Лаборатория кода FIDO2