1- قبل البدء
تطرح حلول المصادقة التقليدية عددًا من التحديات المتعلقة بالأمان وسهولة الاستخدام.
تُستخدَم كلمات المرور على نطاق واسع، ولكن...
- سهلة النسيان
- يحتاج المستخدمون إلى معرفة كيفية إنشاء كلمات مرور قوية.
- يسهل على المهاجمين التصيّد الاحتيالي وجمع البيانات وإعادة استخدامها.
عمل نظام التشغيل Android على إنشاء واجهة برمجة التطبيقات Credential Manager API لتبسيط تجربة تسجيل الدخول ومعالجة المخاطر الأمنية من خلال توفير مفاتيح المرور، وهي الجيل التالي من المعايير المتّبعة في المجال لإثبات الهوية بدون كلمة مرور.
تجمع Credential Manager بين إمكانية استخدام مفاتيح المرور وطرق المصادقة التقليدية، مثل كلمات المرور وميزة "تسجيل الدخول باستخدام حساب Google" وغيرها.
سيتمكّن المستخدمون من إنشاء مفاتيح مرور وتخزينها في "مدير كلمات المرور في Google"، ما سيؤدي إلى مزامنة مفاتيح المرور هذه على جميع أجهزة Android التي سجّل المستخدم الدخول إليها. يجب إنشاء مفتاح مرور وربطه بحساب مستخدم وتخزين مفتاحه العام على خادم قبل أن يتمكّن المستخدم من تسجيل الدخول باستخدامه.
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية الاشتراك باستخدام مفاتيح المرور وكلمات المرور من خلال Credential Manager API واستخدامها لأغراض المصادقة المستقبلية. يتضمّن هذا القسم مسارين، هما:
- الاشتراك : باستخدام مفاتيح المرور وكلمة المرور
- تسجيل الدخول : باستخدام مفاتيح المرور وكلمة المرور المحفوظة
المتطلبات الأساسية
- فهم أساسي لكيفية تشغيل التطبيقات في "استوديو Android"
- فهم أساسي لمسار المصادقة في تطبيقات Android
- فهم أساسي لمفاتيح المرور
أهداف الدورة التعليمية
- كيفية إنشاء مفتاح مرور
- كيفية حفظ كلمة المرور في مدير كلمات المرور
- كيفية مصادقة المستخدمين باستخدام مفتاح مرور أو كلمة مرور محفوظة
المتطلبات
إحدى مجموعات الأجهزة التالية:
- جهاز Android يعمل بالإصدار 9 أو إصدار أحدث (للمفاتيح) والإصدار 4.4 أو إصدار أحدث(لمصادقة كلمة المرور من خلال Credential Manager API)
- يُفضّل أن يكون الجهاز مزوّدًا بأداة استشعار للمقاييس الحيوية.
- احرص على تسجيل قفل شاشة (بصمة الإصبع أو غير ذلك).
- إصدار مكوّن Kotlin الإضافي : 1.8.10
2. طريقة الإعداد
يتطلّب هذا التطبيق النموذجي ربط أصول رقمية بموقع إلكتروني كي يتحقّق Credential Manager من الربط ويتابع، لذا فإنّ معرّف rp المستخدَم في الردود الوهمية مأخوذ من خادم وهمي تابع لجهة خارجية. إذا أردت تجربة ردّ تجريبي خاص بك، حاوِل إضافة نطاق تطبيقك ولا تنسَ إكمال عملية ربط الأصول الرقمية كما هو موضّح هنا.
استخدِم ملف debug.keystore نفسه المذكور في المشروع لإنشاء صيغ تصحيح الأخطاء وإصدارها من أجل التحقّق من ربط مواد العرض الرقمية باسم الحزمة وsha على الخادم التجريبي. (يتم ذلك تلقائيًا في تطبيق العيّنة في ملف build.gradle).
- استنسِخ هذا المستودع على الكمبيوتر المحمول من فرع credman_codelab: https://github.com/android/identity-samples/tree/credman_codelab
git clone -b credman_codelab https://github.com/android/identity-samples.git
- انتقِل إلى وحدة CredentialManager وافتح المشروع في "استوديو Android".
لنطّلِع على الحالة الأولية للتطبيق
لمعرفة طريقة عمل الحالة الأولية للتطبيق، اتّبِع الخطوات التالية:
- افتح التطبيق.
- تظهر لك شاشة رئيسية تتضمّن زرَّي "اشتراك" و"تسجيل الدخول". لا تفعل هذه الأزرار أي شيء حتى الآن، ولكنّنا سنفعِّل وظائفها في الأقسام القادمة.

3- إضافة إمكانية الاشتراك باستخدام مفاتيح المرور
عند الاشتراك في حساب جديد على تطبيق Android يستخدم واجهة برمجة التطبيقات Credential Manager، يمكن للمستخدمين إنشاء مفتاح مرور لحساباتهم. سيتم تخزين مفتاح المرور هذا بشكل آمن لدى موفّر بيانات الاعتماد الذي يختاره المستخدم، وسيتم استخدامه لتسجيل الدخول في المستقبل بدون أن يُطلب من المستخدم إدخال كلمة المرور في كل مرة.
الآن، عليك إنشاء مفتاح مرور وتسجيل بيانات اعتماد المستخدم باستخدام المقاييس الحيوية أو قفل الشاشة.
الاشتراك باستخدام مفتاح مرور
يحدّد الرمز داخل CredentialManager/app/src/main/java/com/google/credentialmanager/sample/SignUpScreen.kt حقل النص "اسم المستخدم" وزرًا للاشتراك باستخدام مفتاح مرور.

تحديد دالة lambda createCredential() لاستخدامها في نماذج العرض
تتطلّب عناصر "إدارة بيانات الاعتماد" تمرير Activity مرتبط بـ Screen. ومع ذلك، يتم عادةً تشغيل عمليات "إدارة بيانات الاعتماد" في "نماذج العرض"، ولا يُنصح بالإشارة إلى الأنشطة ضِمن "نماذج العرض". لذلك، نحدّد وظائف "مدير بيانات الاعتماد" في ملف منفصل CredentialManagerUtil.kt ونشير إليها في الشاشات المناسبة، والتي بدورها تنقلها إلى "نماذج العرض" كدوال ردّ نداء من خلال دوال lambda.
ابحث عن التعليق TODO في الدالة createCredential() في CredentialManagerUtil.kt واستدعِ الدالة CredentialManager.create():
CredentialManagerUtil.kt
suspend fun createCredential(
activity: Activity,
request: CreateCredentialRequest
): CreateCredentialResponse {
TODO("Create a CredentialManager object and call createCredential() with a CreateCredentialRequest")
val credentialManager = CredentialManager.create(activity)
return credentialManager.createCredential(activity, request)
}
تمرير التحدي واستجابة json الأخرى إلى استدعاء createPasskey()
قبل إنشاء مفتاح مرور، عليك طلب المعلومات اللازمة من الخادم ليتم تمريرها إلى Credential Manager API أثناء استدعاء createCredential().
يتوفّر لديك حاليًا ردّ تجريبي في مواد العرض الخاصة بمشروعك، باسم RegFromServer.txt، يعرض المَعلمات اللازمة في هذا الدرس العملي.
- في تطبيقك، انتقِل إلى
SignUpViewModel.kt، وابحث عن طريقةsignUpWithPasskeysالتي ستكتب فيها منطق إنشاء مفتاح مرور والسماح للمستخدم بتسجيل الدخول. يمكنك العثور على الطريقة في الفئة نفسها. - ابحث عن كتلة التعليقات
TODOإلىcreate a CreatePublicKeyCredentialRequest()واستبدلها بالرمز التالي:
SignUpViewModel.kt
TODO("Create a CreatePublicKeyCredentialRequest() with necessary registration json from server")
val request = CreatePublicKeyCredentialRequest(
jsonProvider.fetchRegistrationJson()
.replace("<userId>", getEncodedUserId())
.replace("<userName>", _username.value)
.replace("<userDisplayName>", _username.value)
.replace("<challenge>", getEncodedChallenge())
)
تقرأ الطريقة jsonProvider.fetchRegistrationJsonFromServer() استجابة JSON PublicKeyCredentialCreationOptions لخادم محاكى من مواد العرض وتعرض JSON التسجيل ليتم تمريره أثناء إنشاء مفتاح المرور. نستبدل بعض قيم العناصر النائبة بإدخالات المستخدمين من تطبيقنا وبعض الحقول المحاكية:
- ملف JSON هذا غير مكتمل ويتضمّن 4 حقول يجب استبدالها.
- يجب أن يكون معرّف المستخدم فريدًا حتى يتمكّن المستخدم من إنشاء مفاتيح مرور متعددة (إذا لزم الأمر). استبدِل
<userId>بالقيمةuserIdالتي تم إنشاؤها. - يجب أن يكون
<challenge>فريدًا أيضًا، لذا ستنشئ تحديًا عشوائيًا فريدًا. الطريقة متوفّرة في الرمز البرمجي.
قد تعرض استجابة الخادم الحقيقي PublicKeyCredentialCreationOptions المزيد من الخيارات. في ما يلي مثال على بعض هذه الحقول:
{
"challenge": String,
"rp": {
"name": String,
"id": String
},
"user": {
"id": String,
"name": String,
"displayName": String
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 1800000,
"attestation": "none",
"excludeCredentials": [],
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
يوضّح الجدول التالي بعض المَعلمات المهمة في عنصر PublicKeyCredentialCreationOptions:
المعلّمات | الأوصاف |
سلسلة عشوائية ينشئها الخادم وتحتوي على إنتروبيا كافية تجعل تخمينها أمرًا غير ممكن. يجب ألّا يقل طوله عن 16 بايت. هذه السمة مطلوبة ولكن لا يتم استخدامها أثناء التسجيل إلا عند إجراء التصديق. | |
معرّف فريد للمستخدم يجب ألا تتضمّن هذه القيمة معلومات تحدِّد الهوية الشخصية، مثل عناوين البريد الإلكتروني أو أسماء المستخدمين. ستكون قيمة عشوائية مؤلّفة من 16 بايت يتم إنشاؤها لكل حساب مناسبة. | |
يجب أن يحتوي هذا الحقل على معرّف فريد للحساب يمكن للمستخدم التعرّف عليه، مثل عنوان بريده الإلكتروني أو اسم المستخدم. سيظهر هذا الاسم في أداة اختيار الحساب. (في حال استخدام اسم مستخدم، استخدِم القيمة نفسها المستخدَمة في مصادقة كلمة المرور). | |
هذا الحقل اختياري، وهو اسم أسهل في الاستخدام للحساب. | |
يتوافق كيان الجهة المعتمِدة مع تفاصيل تطبيقك. تتضمّن هذه السمة السمات التالية:
| |
قائمة بالخوارزميات وأنواع المفاتيح المسموح بها يجب أن تحتوي هذه القائمة على عنصر واحد على الأقل. | |
قد يكون المستخدم الذي يحاول تسجيل جهاز قد سجّل أجهزة أخرى. للحدّ من إنشاء بيانات اعتماد متعددة للحساب نفسه على أداة مصادقة واحدة، يمكنك تجاهل هذه الأجهزة. يجب أن يحتوي العنصر | |
تشير هذه السمة إلى ما إذا كان يجب ربط الجهاز بالمنصة أم لا أو إذا لم يكن هناك شرط للقيام بذلك. اضبط هذه القيمة على | |
| أدخِل القيمة |
إنشاء بيانات اعتماد
- بعد إنشاء
CreatePublicKeyCredentialRequest()، عليك استدعاء الدالةcreateCredential()مع الطلب الذي تم إنشاؤه.
SignUpViewModel.kt
try {
TODO("Call createCredential() with createPublicKeyCredentialRequest")
createCredential(request)
TODO("Complete the registration process after sending public key credential to your server and let the user in")
} catch (e: CreateCredentialException) {
handlePasskeyFailure(e)
}
- عليك التعامل مع إمكانية ظهور طرق العرض المعروضة والتعامل مع الاستثناءات في حال تعذّر تنفيذ الطلب أو عدم نجاحه لسبب ما. يتم هنا تسجيل رسائل الخطأ وعرضها في التطبيق في مربّع حوار خاص بالأخطاء. يمكنك الاطّلاع على سجلّات الأخطاء الكاملة من خلال "استوديو Android" أو الأمر
adb debug.

- أخيرًا، عليك إكمال عملية التسجيل. يرسل التطبيق بيانات اعتماد المفتاح العام إلى الخادم الذي يسجّلها للمستخدم الحالي.
في هذا المثال، استخدَمنا خادمًا وهميًا، لذا سنعرض القيمة "صحيح" فقط للإشارة إلى أنّ الخادم قد حفظ المفتاح العام المسجَّل لأغراض المصادقة والتحقّق في المستقبل. يمكنك الاطّلاع على مزيد من المعلومات حول تسجيل مفتاح المرور من جهة الخادم لتنفيذه بنفسك.
داخل طريقة signUpWithPasskeys()، ابحث عن التعليق ذي الصلة واستبدِله بالرمز التالي:
SignUpViewModel.kt
try {
createCredential(request)
TODO("Complete the registration process after sending public key credential to your server and let the user in")
registerResponse()
DataProvider.setSignedInThroughPasskeys(true)
_navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = true))
} catch (e: CreateCredentialException) {
handlePasskeyFailure(e)
}
- تعرض
registerResponse()القيمةtrueللإشارة إلى أنّ الخادم الوهمي قد حفظ المفتاح العام لاستخدامه في المستقبل. - اضبط علامة
setSignedInThroughPasskeysعلىtrue. - بعد تسجيل الدخول، عليك إعادة توجيه المستخدم إلى الشاشة الرئيسية.
قد يحتوي PublicKeyCredential حقيقي على المزيد من الحقول. في ما يلي مثال على هذه الحقول:
{
"id": String,
"rawId": String,
"type": "public-key",
"response": {
"clientDataJSON": String,
"attestationObject": String,
}
}
يوضّح الجدول التالي بعض المَعلمات المهمة في عنصر PublicKeyCredential:
المعلّمات | الأوصاف |
معرّف مشفّر بنظام Base64URL لمفتاح المرور الذي تم إنشاؤه يساعد هذا المعرّف المتصفّح في تحديد ما إذا كان مفتاح مرور مطابقًا متوفّرًا على الجهاز عند المصادقة. يجب تخزين هذه القيمة في قاعدة البيانات على الخلفية. | |
تمثّل هذه السمة إصدار العنصر من معرّف بيانات الاعتماد. | |
عنصر | |
كائن شهادة مشفّر |
شغِّل التطبيق، وسيصبح بإمكانك النقر على الزر الاشتراك باستخدام مفاتيح المرور وإنشاء مفتاح مرور.
4. حفظ كلمة مرور في Credential Provider
في هذا التطبيق، داخل شاشة "الاشتراك"، لديك حاليًا عملية اشتراك باستخدام اسم المستخدم وكلمة المرور لأغراض توضيحية.
لحفظ بيانات اعتماد كلمة مرور المستخدم لدى مقدّم خدمة كلمات المرور، عليك تنفيذ CreatePasswordRequest لتمريرها إلى createCredential() من أجل حفظ كلمة المرور.
- ابحث عن طريقة
signUpWithPassword()، واستبدِل TODO باستدعاءcreatePassword:
SignUpViewModel.kt
TODO("CreatePasswordRequest with entered username and password")
val passwordRequest = CreatePasswordRequest(_username.value, _password.value)
- بعد ذلك، أنشئ بيانات اعتماد باستخدام طلب إنشاء كلمة مرور واحفظ بيانات اعتماد كلمة مرور المستخدم لدى مقدّم خدمة كلمات المرور. بعد ذلك، سجِّل دخول المستخدم. نحن نرصد الاستثناءات التي تحدث في هذا المسار بشكل أكثر عمومية. استبدِل TODO بالرمز التالي:
SignUpViewModel.kt
TODO("Create credential with created password request and log the user in")
try {
createCredential(passwordRequest)
simulateServerDelayAndLogIn()
} catch (e: Exception) {
val errorMessage = "Exception Message : " + e.message
Log.e("Auth", errorMessage)
_passwordCreationError.value = errorMessage
_isLoading.value = false
}
لقد حفظت الآن بيانات اعتماد كلمة المرور بنجاح باستخدام موفّر كلمة مرور المستخدم للمصادقة باستخدام كلمة مرور بنقرة واحدة فقط.
5- إضافة إمكانية المصادقة باستخدام مفتاح مرور أو كلمة مرور
أنت الآن جاهز لاستخدامه كوسيلة للمصادقة على تطبيقك بأمان.

تحديد دالة lambda getCredential() لاستخدامها في نماذج العرض
كما في السابق، سنستدعي getCredential() في "مدير بيانات الاعتماد" في ملف منفصل CredentialManagerUtil.kt لاستخدامه كمرجع في الشاشات المناسبة وتمريره إلى "نماذج العرض" كبرامج معالجة من خلال دوال lambda.
ابحث عن التعليق TODO في الدالة getCredential() في CredentialManagerUtil.kt واستدعِ الدالة CredentialManager.get():
suspend fun getCredential(
activity: Activity,
request: GetCredentialRequest
): GetCredentialResponse {
TODO("Create a CredentialManager object and call getCredential() with a GetCredentialRequest")
val credentialManager = CredentialManager.create(activity)
return credentialManager.getCredential(activity, request)
}
الحصول على التحدي وخيارات أخرى لتمريرها إلى استدعاء getPasskey()
قبل أن تطلب من المستخدم إثبات الهوية، عليك طلب مَعلمات لتمريرها في WebAuthn JSON من الخادم، بما في ذلك سؤال التحقّق.
لديك حاليًا ردّ تجريبي في مواد العرض (AuthFromServer.txt) يعرض مَعلمات من هذا النوع في هذا الدرس العملي.
- في تطبيقك، انتقِل إلى SignInViewModel.kt، وابحث عن الطريقة
signInWithSavedCredentialsالتي ستكتب فيها منطق المصادقة من خلال مفتاح المرور أو كلمة المرور المحفوظة والسماح للمستخدم بتسجيل الدخول: - أنشئ GetPublicKeyCredentialOption() مع المَعلمات اللازمة المطلوبة للحصول على بيانات الاعتماد من مقدّم خدمة بيانات الاعتماد.
SignInViewModel.kt
TODO("Create a GetPublicKeyCredentialOption() with necessary authentication json from server")
val getPublicKeyCredentialOption =
GetPublicKeyCredentialOption(jsonProvider.fetchAuthJson(), null)
تقرأ طريقة fetchAuthJsonFromServer() استجابة JSON للمصادقة من مواد العرض وتعرض JSON للمصادقة من أجل استرداد جميع مفاتيح المرور المرتبطة بحساب المستخدم هذا.
المَعلمة الثانية للدالة GetPublicKeyCredentialOption() هي clientDataHash، وهي عبارة عن قيمة تجزئة تُستخدَم للتحقّق من هوية الجهة المعتمِدة. اضبط هذه السمة فقط إذا كنت قد ضبطت السمة GetCredentialRequest.origin. بالنسبة إلى التطبيق النموذجي، تم ضبط هذا الخيار على null.
ملاحظة : تم تصميم خادم هذا الدرس العملي لكي يعرض ملف JSON مشابهًا قدر الإمكان لقائمة PublicKeyCredentialRequestOptions التي يتم تمريرها إلى طلب getCredential() لواجهة برمجة التطبيقات. يتضمّن مقتطف الرمز التالي بعض الأمثلة على الخيارات التي يمكن أن تتلقّاها في ردّ حقيقي:
{
"challenge": String,
"rpId": String,
"userVerification": "",
"timeout": 1800000
}
يوضّح الجدول التالي بعض المَعلمات المهمة في عنصر PublicKeyCredentialRequestOptions:
المعلّمات | الأوصاف |
تحدٍ من إنشاء الخادم في عنصر | |
رقم تعريف الجهة الاعتمادية هو نطاق. يمكن للموقع الإلكتروني تحديد نطاقه أو لاحقة قابلة للتسجيل. يجب أن تتطابق هذه القيمة مع المَعلمة |
- بعد ذلك، عليك إنشاء عنصر
PasswordOption()لاسترداد جميع كلمات المرور المحفوظة في موفّر كلمات المرور من خلال Credential Manager API لحساب المستخدم هذا. داخل طريقةgetSavedCredentials()، ابحث عن TODO واستبدِله بما يلي:
SigninViewModel.kt
TODO("Create a PasswordOption to retrieve all the associated user's password")
val getPasswordOption = GetPasswordOption()
اجمع هذه القيم في GetCredentialRequest.
SigninViewModel.kt
TODO("Combine requests into a GetCredentialRequest")
val request = GetCredentialRequest(
listOf(
getPublicKeyCredentialOption,
getPasswordOption
)
)
الحصول على بيانات الاعتماد
بعد ذلك، عليك إرسال طلب getCredential() مع جميع الخيارات المذكورة أعلاه لاسترداد بيانات الاعتماد المرتبطة:
SignInViewModel.kt
try {
TODO("Call getCredential() with required credential options")
val result = getCredential(request)
val data = when (result.credential) {
is PublicKeyCredential -> {
val cred = result.credential as PublicKeyCredential
DataProvider.setSignedInThroughPasskeys(true)
"Passkey: ${cred.authenticationResponseJson}"
}
is PasswordCredential -> {
val cred = result.credential as PasswordCredential
DataProvider.setSignedInThroughPasskeys(false)
"Got Password - User:${cred.id} Password: ${cred.password}"
}
is CustomCredential -> {
//If you are also using any external sign-in libraries, parse them here with the utility functions provided.
null
}
else -> null
}
TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
} catch (e: Exception) {
Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
_signInError.value =
"An error occurred while authenticating: " + e.message.toString()
} finally {
_isLoading.value = false
}
- يمكنك تمرير المعلومات المطلوبة إلى
getCredential(). يأخذ هذا الإجراء قائمة بخيارات بيانات الاعتماد وسياق نشاط لعرض الخيارات في ورقة أسفل الشاشة في هذا السياق. - بعد نجاح الطلب، سيظهر لك ورقة في أسفل الشاشة تعرض جميع بيانات الاعتماد التي تم إنشاؤها للحساب المرتبط.
- يمكن للمستخدمين الآن إثبات هويتهم من خلال المقاييس الحيوية أو قفل الشاشة وما إلى ذلك للمصادقة على بيانات الاعتماد المحدّدة.
- إذا كانت بيانات الاعتماد المحدّدة هي
PublicKeyCredential، اضبط العلامةsetSignedInThroughPasskeysعلىtrue. بخلاف ذلك، اضبطها علىfalse.
يتضمّن مقتطف الرمز التالي مثالاً على الكائن PublicKeyCredential:
{
"id": String
"rawId": String
"type": "public-key",
"response": {
"clientDataJSON": String
"authenticatorData": String
"signature": String
"userHandle": String
}
}
الجدول التالي ليس شاملاً، ولكنّه يتضمّن المَعلمات المهمة في العنصر PublicKeyCredential:
المعلّمات | الأوصاف |
رقم التعريف المشفّر Base64URL لبيانات اعتماد مفتاح المرور التي تمّت المصادقة عليها. | |
تمثّل هذه السمة إصدار العنصر من معرّف بيانات الاعتماد. | |
عنصر | |
عنصر | |
عنصر | |
عنصر |
- أخيرًا، عليك إكمال عملية المصادقة. عادةً، بعد أن يكمل المستخدم مصادقة مفتاح المرور، يرسل التطبيق بيانات اعتماد المفتاح العام التي تحتوي على تأكيد المصادقة إلى الخادم الذي يتحقّق من التأكيد ويصادق على المستخدم.
في هذه الحالة، استخدمنا خادمًا وهميًا، لذا نعرض true فقط للإشارة إلى أنّ الخادم قد تحقّق من صحة التأكيد. يمكنك الاطّلاع على مزيد من المعلومات حول مصادقة مفتاح المرور من جهة الخادم لتنفيذها بنفسك.
داخل طريقة signInWithSavedCredentials()، ابحث عن التعليق ذي الصلة واستبدِله بالرمز التالي:
SignInViewModel.kt
TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
if (data != null) {
sendSignInResponseToServer()
_navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = DataProvider.isSignedInThroughPasskeys()))
}
- تعرض
sendSigninResponseToServer()القيمة "صحيح"، ما يشير إلى أنّ الخادم (الوهمي) قد تحقّق من صحة المفتاح العام لاستخدامه في المستقبل. - بعد تسجيل الدخول، عليك إعادة توجيه المستخدم إلى الشاشة الرئيسية.
شغِّل التطبيق وانتقِل إلى تسجيل الدخول > تسجيل الدخول باستخدام مفاتيح المرور/كلمة المرور المحفوظة، وحاوِل تسجيل الدخول باستخدام بيانات الاعتماد المحفوظة.
تجربة الميزة
لقد نفّذت عملية إنشاء مفاتيح مرور وحفظ كلمات المرور في Credential Manager والمصادقة من خلال مفاتيح المرور أو كلمات المرور المحفوظة باستخدام واجهة برمجة التطبيقات Credential Manager في تطبيق Android.
6. تهانينا!
لقد أكملت هذا الدرس التطبيقي حول الترميز. إذا أردت الاطّلاع على الحل النهائي المتوفّر على https://github.com/android/identity-samples/tree/main/CredentialManager
إذا كانت لديك أي أسئلة، يمكنك طرحها على StackOverflow باستخدام علامة passkey.