قبل أن يتمكّن المستخدمون من المصادقة باستخدام مفاتيح المرور، يجب أن يسجّل تطبيقك مفتاح المرور أو ينشئه أولاً لحساباتهم.
لإنشاء مفتاح المرور، احصل على التفاصيل المطلوبة من خادم تطبيقك، ثم استدعِ Credential Manager API، الذي يعرض زوجًا من المفاتيح العامة والخاصة. يتم تخزين المفتاح الخاص الذي يتم عرضه في موفّر بيانات الاعتماد، مثل "مدير كلمات المرور في Google"، كمفتاح مرور. ويتم تخزين المفتاح العام على خادم تطبيقك.
المتطلبات الأساسية
تأكَّد من إعداد روابط تنقل إلى مواد عرض رقمية واستهداف الأجهزة التي تعمل بالإصدار 9 من Android (المستوى 28 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث.
نظرة عامة
يركّز هذا الدليل على التغييرات المطلوبة في تطبيق العميل التابع لجهة الاعتماد لإنشاء مفتاح مرور، ويقدّم نظرة عامة موجزة عن تنفيذ خادم تطبيق جهة الاعتماد. لمزيد من المعلومات عن عملية الدمج من جهة الخادم، يُرجى الاطّلاع على تسجيل مفتاح المرور من جهة الخادم.
- إضافة التبعيات إلى تطبيقك: أضِف مكتبات Credential Manager المطلوبة.
- إنشاء مثيل لـ Credential Manager: أنشئ مثيلاً لـ Credential Manager.
- الحصول على خيارات إنشاء بيانات الاعتماد من خادم التطبيق: من خادم تطبيقك
، أرسِل إلى تطبيق العميل التفاصيل المطلوبة لإنشاء مفتاح المرور، مثل
معلومات عن التطبيق والمستخدم، بالإضافة إلى
challengeوحقول أخرى. - طلب مفتاح مرور: في تطبيقك، استخدِم التفاصيل التي تم تلقّيها من خادم التطبيق
لإنشاء عنصر
GetPublicKeyCredentialOptionواستخدِم هذا العنصر لاستدعاء طريقةcredentialManager.getCredential()لإنشاء مفتاح مرور. - التعامل مع الردّ على إنشاء مفتاح المرور: عند تلقّي بيانات الاعتماد على تطبيق العميل، عليك ترميز المفتاح العام وتسلسله ثم إرساله إلى خادم التطبيق. عليك أيضًا التعامل مع كل الاستثناءات التي يمكن أن تحدث في حال إنشاء مفتاح المرور.
- التحقّق من المفتاح العام وحفظه على الخادم: أكمل الخطوات من جهة الخادم للتحقّق من مصدر بيانات الاعتماد، ثم احفظ المفتاح العام.
- إعلام المستخدم: أرسِل إشعارًا إلى المستخدم يفيد بأنّه تم إنشاء مفتاح المرور.
إضافة التبعيات إلى تطبيقك
أضِف التبعيات التالية إلى ملف build.gradle لوحدة تطبيقك:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.7.0-alpha02") implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha02") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.7.0-alpha02" implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha02" }
إنشاء مثيل لـ Credential Manager
استخدِم سياق تطبيقك أو نشاطك لإنشاء عنصر 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: تُستخدَم هذه القيمة للأجهزة المتجوّلة، مثل مفاتيح الأمان. لا تُستخدَم عادةً في سياق مفتاح المرور. - غير محدّد (ننصح بذلك): يمنح ترك هذه القيمة غير محدّدة المستخدمين المرونة لإنشاء مفاتيح مرور على أجهزتهم المفضّلة. في معظم الحالات، يكون ترك المَعلمة غير محدّدة هو الخيار الأفضل.requireResidentKey: لإنشاء مفتاح مرور، اضبط قيمة هذا الحقلBooleanعلىtrue.residentKey: لإنشاء مفتاح مرور، اضبط القيمة علىrequired.userVerification: تُستخدَم لتحديد متطلبات التحقّق من هوية المستخدم أثناء تسجيل مفتاح المرور. في ما يلي القيم المحتمَلة: -preferred: استخدِم هذه القيمة إذا كنت تعطي الأولوية لتجربة المستخدم على الحماية، مثلاً في البيئات التي يتسبب فيها التحقّق من هوية المستخدم في احتكاك أكبر من الحماية. -required: استخدِم هذه القيمة إذا كان استدعاء طريقة التحقّق من هوية المستخدم المتوفّرة على الجهاز مطلوبًا. -discouraged: استخدِم هذه القيمة إذا كان استخدام طريقة التحقّق من هوية المستخدم غير مستحسَن.
لمزيد من المعلومات عنuserVerification، يُرجى الاطّلاع على مقالة نظرة متعمّقة على userVerification.
excludeCredentials: أدرِج معرّفات بيانات الاعتماد في مصفوفة لمنع إنشاء مفتاح مرور مكرّر إذا كان هناك مفتاح حالي لدى موفّر بيانات الاعتماد نفسه.
إنشاء مفتاح مرور
بعد تحليل خيارات إنشاء المفتاح العام من جهة الخادم، أنشئ مفتاح مرور عن طريق تضمين هذه الخيارات في عنصر CreatePublicKeyCredentialRequest واستدعاء createCredential().
يتضمّن createPublicKeyCredentialRequest ما يلي:
requestJson: خيارات إنشاء بيانات الاعتماد التي أرسلها خادم التطبيقpreferImmediatelyAvailableCredentials: هذا حقل منطقي اختياري يحدّد ما إذا كان يجب استخدام بيانات الاعتماد المتوفّرة محليًا أو بيانات الاعتماد التي تمت مزامنتها مع موفّر بيانات الاعتماد فقط لتلبية الطلب، بدلاً من بيانات الاعتماد من مفاتيح الأمان أو مسارات المفاتيح المختلطة. في ما يلي الاستخدامات المحتمَلة:false(تلقائي): استخدِم هذه القيمة إذا تم استدعاء Credential Manager من خلال إجراء صريح من المستخدم.true: استخدِم هذه القيمة إذا تم استدعاء Credential Manager بشكل انتهازي، مثلاً عند فتح التطبيق لأول مرة.
إذا ضبطت القيمة علىtrueولم تكن هناك بيانات اعتماد متوفّرة على الفور، لن يعرض Credential Manager أي واجهة مستخدم وسيفشل الطلب على الفور، ما يؤدي إلى عرض NoCredentialException لطلبات الحصول على بيانات الاعتماد وCreateCredentialNoCreateOptionExceptionلطلبات الإنشاء.
origin: يتم ضبط هذا الحقل تلقائيًا لتطبيقات Android. بالنسبة إلى المتصفّحات و التطبيقات المماثلة التي تتمتع بامتيازات والتي تحتاج إلى ضبطorigin، يُرجى الاطّلاع على مقالة إجراء استدعاءات Credential Manager نيابةً عن جهات أخرى للتطبيقات التي تتمتع بامتيازات.isConditional: هذا حقل اختياري يتم ضبطه تلقائيًا علىfalse. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة إنشاء مفتاح مرور تلقائيًا.
يؤدي استدعاء الدالة createCredential() إلى تشغيل واجهة مستخدم ورقة البيانات السفلية المضمّنة في Credential Manager، والتي تطلب من المستخدم استخدام مفتاح مرور واختيار موفّر بيانات اعتماد وحساب للتخزين. ومع ذلك، إذا تم ضبط isConditional على true، لن يتم عرض واجهة مستخدم ورقة البيانات السفلية، وسيتم إنشاء مفتاح المرور تلقائيًا.
إنشاء مفتاح مرور تلقائيًا
يمكنك إنشاء مفتاح مرور تلقائيًا للمستخدم بعد تسجيل الدخول بنجاح باستخدام كلمة المرور عن طريق ضبط المَعلمة isConditional على true في CreatePublicKeyCredentialRequest أثناء إنشاء مفتاح مرور. إذا لم يكن لدى المستخدم مفتاح مرور، سيحاول تطبيقك تلقائيًا إنشاء مفتاح في الخلفية وتخزينه في موفّر بيانات اعتماد المستخدم، مثل "مدير كلمات المرور في Google". للاطّلاع على مثال عن كيفية تنفيذ ذلك، يُرجى الاطّلاع على
النموذج العلني.
التعامل مع الردّ
بعد التحقّق من هوية المستخدم باستخدام قفل شاشة الجهاز، يتم إنشاء مفتاح مرور وتخزينه في موفّر بيانات الاعتماد الذي اختاره المستخدم.
الردّ بعد استدعاء 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.استخدِم ترميز base64url لترميز الملف المرجعي لشهادة SHA-256. يوضّح مثال 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 إلى تسجيل دخول المستخدمين عند فتح التطبيق الذي تم استعادته على جهاز جديد، ما يتيح لهم استخدام تطبيقك على الفور.
إيقاف الملء التلقائي في حقول بيانات الاعتماد (اختياري)
بالنسبة إلى شاشات التطبيق التي يُتوقَّع أن يستخدم فيها المستخدمون واجهة مستخدم ورقة البيانات السفلية في Credential Manager للمصادقة، أضِف السمة isCredential إلى حقلَي اسم المستخدم وكلمة المرور. يؤدي ذلك إلى إيقاف مربّعات حوار الملء التلقائي (FillDialog وSaveDialog) من التداخل مع واجهة مستخدم ورقة البيانات السفلية في Credential Manager.
تتوفّر السمة isCredential على Android 14 والإصدارات الأحدث.
يوضّح المثال التالي كيفية إضافة السمة isCredential إلى حقلَي اسم المستخدم وكلمة المرور ذَوَي الصلة في طرق العرض ذات الصلة لتطبيقك:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true" />