توفّر واجهة برمجة التطبيقات Credential Manager API إمكانية استخدام مفاتيح المرور وتسجيل الدخول الموحّد وموفّري مصادقة تابعين لجهات خارجية، وهي واجهة برمجة التطبيقات المُقترَحة للقيام بمهام مصادقة على Android، حيث توفّر بيئة آمنة ومريحة تسمح للمستخدمين بمزامنة بيانات الاعتماد الخاصة بهم وإدارتها. على المطوّرين الذين يستخدمون بيانات اعتماد FIDO2 المحلية تحديث تطبيقك لإتاحة مصادقة مفتاح المرور من خلال الدمج مع واجهة برمجة تطبيقات Credential Manager API. يصف هذا المستند كيفية نقل مشروعك من FIDO2 إلى Credential Manager.
أسباب نقل البيانات من FIDO2 إلى "أداة إدارة بيانات الاعتماد"
في معظم الحالات، عليك نقل مقدّم خدمة المصادقة لتطبيق Android إلى مدير بيانات الاعتماد. تشمل أسباب الانتقال إلى "مدير بيانات الاعتماد" ما يلي:
- إتاحة استخدام مفاتيح المرور: يتيح "مدير بيانات الاعتماد" استخدام مفاتيح المرور، وهي آلية مصادقة جديدة بدون كلمة مرور وأكثر أمانًا وسهولة في الاستخدام مقارنةً بكلمات المرور.
- طرق تسجيل دخول متعددة: يتيح "مدير بيانات الاعتماد" استخدام عدة methods تسجيل دخول، بما في ذلك كلمات المرور ومفاتيح المرور وطرق تسجيل الدخول المُدار. ويسهّل ذلك على المستخدمين مصادقة هويتهم في تطبيقك، بغض النظر عن طريقة المصادقة المفضّلة لديهم.
- إتاحة موفِّري بيانات اعتماد تابعين لجهات خارجية: على نظام التشغيل Android 14 والإصدارات الأحدث، يتوافق "مدير بيانات الاعتماد" مع موفِّري بيانات اعتماد تابعين لجهات خارجية. ويعني ذلك أنّه يمكن للمستخدمين استخدام بيانات الاعتماد الحالية من مقدّمي خدمات آخرين لتسجيل الدخول إلى تطبيقك.
- تجربة مستخدم متّسقة: يوفّر "مدير بيانات الاعتماد" تجربة مستخدم أكثر اتساقًا للمصادقة في جميع التطبيقات وآليات تسجيل الدخول. ويسهّل ذلك على المستخدمين فهم عملية مصادقة تطبيقك واستخدامها.
لبدء نقل البيانات من FIDO2 إلى "مدير بيانات الاعتماد"، اتّبِع الخطوات أدناه.
تعديل التبعيات
حدِّث المكوّن الإضافي بلغة Kotlin في الإصدار create.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()
من واجهة برمجة تطبيقات "إدارة بيانات الاعتماد". استدعاء طريقة واجهة برمجة التطبيقاتcreateCredential()
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") { } }
يمكنك إزالة أي طرق تتعامل مع مشغّل intent ومكالمات النشاط من العرض بأمان.
بما أنّ
signInRequest()
يعرض الآنJSONObject
، لا تحتاج إلى إنشاءPendingIntent
. استبدِل النية التي تم عرضها بJSONObject
، واطلبgetCredential()
من طرق واجهة برمجة التطبيقات.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 }
بعد نجاح المكالمة، أرسِل الاستجابة مرة أخرى إلى الخادم لتأكيد هوية المستخدم ومصادقته. تشبه مَعلمات الطلب والاستجابة لمحاولة الاتصال هذه لواجهة برمجة التطبيقات عملية تنفيذ FIDO2، لذا ليس مطلوبًا إجراء أي تغييرات.
مصادر إضافية
- نموذج مرجعي لـ Credential Manager
- الدرس التطبيقي حول أداة "إدارة بيانات الاعتماد"
- توفير مصادقة سلسة لتطبيقاتك باستخدام مفاتيح المرور من خلال واجهة برمجة التطبيقات Credential Manager API
- FIDO2 codelab