يواصل هذا الدليل شرح كيفية استخدام مفاتيح المرور للمصادقة. قبل أن يتمكّن المستخدمون من تسجيل الدخول باستخدام مفاتيح المرور، عليك أيضًا إكمال الـ تعليمات الواردة في إنشاء مفاتيح المرور.
للمصادقة باستخدام مفتاح مرور، عليك أولاً استرداد الخيارات المطلوبة لاسترداد المفتاح العام من خادم تطبيقك، ثم استدعاء واجهة برمجة التطبيقات Credential Manager لاسترداد المفتاح العام. بعد ذلك، عليك معالجة استجابة تسجيل الدخول بشكل مناسب.
نظرة عامة
يركّز هذا الدليل على التغييرات المطلوبة في تطبيق العميل لتسجيل دخول المستخدم باستخدام مفتاح مرور، ويقدّم نظرة عامة موجزة عن عملية التنفيذ من جهة خادم التطبيق. لمزيد من المعلومات عن عملية التكامل من جهة الخادم، يُرجى الاطّلاع على مقالة المصادقة باستخدام مفتاح مرور من جهة الخادم.
لاسترداد جميع خيارات مفاتيح المرور وكلمات المرور المرتبطة بحساب المستخدم، يُرجى إكمال الخطوات التالية:
- الحصول على خيارات طلب بيانات الاعتماد من الخادم: أرسِل طلبًا من تطبيقك إلى خادم المصادقة لبدء عملية تسجيل الدخول باستخدام مفتاح المرور. من الخادم، أرسِل الخيارات المطلوبة للحصول على بيانات اعتماد المفتاح العام، بالإضافة إلى تحدٍّ فريد.
- إنشاء الكائن المطلوب للحصول على بيانات اعتماد المفتاح العام: ضَع
الخيارات التي أرسلها الخادم في كائن
GetPublicKeyCredentialOption - (اختياري) إعداد `getCredential`: في الإصدار 14 من Android والإصدارات الأحدث، يمكنك
تقليل وقت الاستجابة من خلال عرض أداة اختيار الحساب باستخدام
prepareGetCredential()قبل استدعاءgetCredential(). - بدء مسار تسجيل الدخول: استدعِ طريقة
getCredential()لتسجيل دخول المستخدم - معالجة الاستجابة: عالِج كل استجابة محتمَلة لبيانات الاعتماد.
- معالجة الاستثناءات: تأكَّد من معالجة الاستثناءات بشكل مناسب.
الحصول على خيارات طلب بيانات الاعتماد من الخادم
اطلب من الخادم الخيارات المطلوبة للحصول على بيانات اعتماد المفتاح العام،
بالإضافة إلى challenge، وهو فريد لكل محاولة تسجيل دخول. لمزيد من المعلومات عن عملية التنفيذ من جهة الخادم، يُرجى الاطّلاع على مقالتَي إنشاء التحدّي وإنشاء خيارات طلب بيانات الاعتماد.
تبدو الخيارات مشابهة لما يلي:
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
لمزيد من المعلومات عن الحقول، يُرجى الاطّلاع على مشاركة المدونة الإلكترونية حول تسجيل الدخول باستخدام مفتاح مرور.
إنشاء الكائن المطلوب للحصول على بيانات اعتماد المفتاح العام
في تطبيقك، استخدِم الخيارات لإنشاء كائن 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
)
اختياري: تقليل وقت الاستجابة لتسجيل الدخول
في الإصدار 14 من Android والإصدارات الأحدث، يمكنك تقليل وقت الاستجابة عند عرض أداة اختيار الحساب
باستخدام الطريقة prepareGetCredential() قبل استدعاء
getCredential().
تعرض طريقة prepareGetCredential() كائن
PrepareGetCredentialResponse يتم تخزينه مؤقتًا. يتيح ذلك لطريقة getCredential() في الخطوة التالية عرض أداة اختيار الحساب باستخدام البيانات المخزّنة مؤقتًا.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
بدء مسار تسجيل الدخول
استدعِ طريقة getCredential() لعرض أداة اختيار الحساب للمستخدم. استخدِم مقتطف الرمز البرمجي التالي كمرجع لكيفية بدء مسار تسجيل الدخول:
// Use an activity-based context to avoid undefined system UI
// launching behavior.
val context = MutableContextWrapper(activityContext)
coroutineScope {
try {
result = credentialManager.getCredential(
// Use MutableContextWrapper to avoid memory leak during configuration changes
context = context,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
معالجة الاستجابة
عالِج الاستجابة التي يمكن أن تحتوي على أحد أنواع كائنات بيانات الاعتماد المختلفة.
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>"
}
}
على الخادم، عليك التحقّق من بيانات الاعتماد. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة التحقّق من هوية المستخدم و تسجيل دخوله.
معالجة الاستثناءات
عليك معالجة جميع استثناءات الفئة الفرعية من GetCredentialException.
لمعرفة كيفية معالجة كل استثناء، يُرجى الاطّلاع على دليل تحديد المشاكل وحلّها.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}