يواصل هذا الدليل شرح كيفية استخدام مفاتيح المرور للمصادقة. قبل أن يتمكّن المستخدمون من تسجيل الدخول باستخدام مفاتيح المرور، عليك أيضًا إكمال التعليمات الواردة في إنشاء مفاتيح مرور.
للمصادقة باستخدام مفتاح مرور، عليك أولاً استرداد الخيارات المطلوبة لاسترداد المفتاح العام من خادم التطبيق، ثم استدعاء واجهة برمجة التطبيقات Credential Manager لاسترداد المفتاح العام. بعد ذلك، عالِج رد تسجيل الدخول بالطريقة المناسبة.
نظرة عامة
يركّز هذا الدليل على التغييرات المطلوبة في تطبيق العميل لتسجيل دخول المستخدم باستخدام مفتاح مرور، ويقدّم نظرة عامة موجزة على عملية التنفيذ من جهة خادم التطبيق. لمزيد من المعلومات عن عملية الربط من جهة الخادم، يُرجى الاطّلاع على مقالة المصادقة باستخدام مفتاح المرور من جهة الخادم.
لاسترداد جميع خيارات مفتاح المرور وكلمة المرور المرتبطة بحساب المستخدم، اتّبِع الخطوات التالية:
- الحصول على خيارات طلب بيانات الاعتماد من الخادم: أرسِل طلبًا من تطبيقك إلى خادم المصادقة لبدء عملية تسجيل الدخول باستخدام مفتاح المرور. من الخادم، أرسِل الخيارات المطلوبة للحصول على بيانات اعتماد المفتاح العام، بالإضافة إلى سؤال تحدٍّ فريد.
- إنشاء العنصر المطلوب للحصول على بيانات اعتماد المفتاح العام: لفّ الخيارات التي يرسلها الخادم في عنصر
GetPublicKeyCredentialOption - (اختياري) إعداد getCredential: في الإصدار 14 من نظام التشغيل Android والإصدارات الأحدث، يمكنك تقليل وقت الاستجابة من خلال عرض أداة اختيار الحساب باستخدام الطريقة
prepareGetCredential()قبل استدعاءgetCredential(). - بدء عملية تسجيل الدخول: استدعاء طريقة
getCredential()لتسجيل دخول المستخدم - التعامل مع الردود: تعامَل مع كل الردود المحتملة على بيانات الاعتماد.
- التعامل مع الاستثناءات: تأكَّد من التعامل مع الاستثناءات بشكل مناسب.
1. الحصول على خيارات طلب بيانات الاعتماد من الخادم
اطلب من الخادم الخيارات المطلوبة للحصول على بيانات اعتماد المفتاح العام، بالإضافة إلى challenge، وهو معرّف فريد لكل محاولة تسجيل دخول. لمزيد من المعلومات حول التنفيذ من جهة الخادم، يُرجى الاطّلاع على إنشاء التحدي وإنشاء خيارات طلب بيانات الاعتماد.
ستبدو الخيارات مشابهة لما يلي:
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
لمزيد من المعلومات حول الحقول، يمكنك الاطّلاع على مشاركة المدونة حول تسجيل الدخول باستخدام مفتاح مرور.
2- إنشاء العنصر المطلوب للحصول على بيانات اعتماد المفتاح العام
في تطبيقك، استخدِم الخيارات لإنشاء عنصر GetPublicKeyCredentialOption.
في المثال التالي، يمثّل requestJson الخيارات التي أرسلها الخادم.
// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()
// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
requestJson = requestJson
)
بعد ذلك، ضع GetPublicKeyCredentialOption في عنصر GetCredentialRequest.
val credentialRequest = GetCredentialRequest(
// Include all the sign-in options that your app supports.
listOf(getPasswordOption, getPublicKeyCredentialOption),
// Defines whether you prefer to use only immediately available
// credentials or hybrid credentials.
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)
3- اختياري: تقليل وقت الاستجابة عند تسجيل الدخول
على نظام التشغيل Android 14 أو الإصدارات الأحدث، يمكنك تقليل وقت الاستجابة عند عرض أداة اختيار الحساب من خلال استخدام طريقة prepareGetCredential() قبل استدعاء getCredential().
تعرض الطريقة prepareGetCredential() عنصر PrepareGetCredentialResponse يتم تخزينه مؤقتًا. يتيح ذلك للطريقة
getCredential() في الخطوة التالية عرض أداة اختيار الحساب
مع البيانات المخزّنة مؤقتًا.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
4- بدء عملية تسجيل الدخول
استدعِ طريقة getCredential() لعرض أداة اختيار الحساب للمستخدم. استخدِم مقتطف الرمز التالي كمرجع حول كيفية بدء عملية تسجيل الدخول:
coroutineScope {
try {
result = credentialManager.getCredential(
// Use an activity-based context to avoid undefined system UI
// launching behavior.
context = activityContext,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
5. التعامل مع الردّ
تعامَل مع الردّ الذي يمكن أن يحتوي على أحد الأنواع المختلفة من عناصر بيانات الاعتماد.
fun handleSignIn(result: GetCredentialResponse) {
// Handle the successfully returned credential.
val credential = result.credential
when (credential) {
is PublicKeyCredential -> {
val responseJson = credential.authenticationResponseJson
// Share responseJson i.e. a GetCredentialResponse on your server to
// validate and authenticate
}
is PasswordCredential -> {
val username = credential.id
val password = credential.password
// Use id and password to send to your server to validate
// and authenticate
}
is CustomCredential -> {
// If you are also using any external sign-in libraries, parse them
// here with the utility functions provided.
if (credential.type == ExampleCustomCredential.TYPE) {
try {
val ExampleCustomCredential =
ExampleCustomCredential.createFrom(credential.data)
// Extract the required credentials and complete the authentication as per
// the federated sign in or any external sign in library flow
} catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
// Unlikely to happen. If it does, you likely need to update the dependency
// version of your external sign-in library.
Log.e(TAG, "Failed to parse an ExampleCustomCredential", e)
}
} else {
// Catch any unrecognized custom credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
}
إنّ PublicKeyCredential الذي يتم إرجاعه من المصادقة هو في الأساس تأكيد موقّع، ويتم تنظيمه على النحو التالي:
{
"id": "<credential ID>",
"type": "public-key",
"rawId": "<raw credential ID>",
"response": {
"clientDataJSON": "<signed client data containing challenge>",
"authenticatorData": "<authenticator metadata>",
"signature": "<digital signature to be verified>",
"userHandle": "<user ID from credential registration>"
}
}
على الخادم، يجب إثبات صحة بيانات الاعتماد. لمزيد من المعلومات، يُرجى الاطّلاع على إثبات هوية المستخدم وتسجيل الدخول.
6. التعامل مع الاستثناءات
عليك التعامل مع جميع استثناءات الفئة الفرعية GetCredentialException.
للتعرّف على كيفية التعامل مع كل استثناء، راجِع دليل تحديد المشاكل وحلّها.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}