Credential Manager هي واجهة برمجة تطبيقات Jetpack تتوافق مع طرق متعددة لتسجيل الدخول، مثل اسم المستخدم وكلمة المرور ومفاتيح المرور وحلول تسجيل الدخول الموحَّدة (مثل "تسجيل الدخول باستخدام حساب Google") في واجهة برمجة تطبيقات واحدة، ما يسهّل عملية الدمج على المطوّرين.
بالإضافة إلى ذلك، يوحّد Credential Manager واجهة تسجيل الدخول عبر طرق المصادقة المختلفة، ما يتيح للمستخدمين تسجيل الدخول إلى التطبيقات بشكل أسهل وأبسط بغض النظر عن الطريقة المستخدَمة.
توضّح هذه الصفحة مفهوم مفاتيح المرور والخطوات اللازمة لتوفير إمكانية استخدام حلول المصادقة، بما في ذلك مفاتيح المرور، من جهة العميل باستخدام واجهة برمجة التطبيقات Credential Manager API. تتوفّر أيضًا صفحة أسئلة شائعة منفصلة تقدّم إجابات عن أسئلة أكثر تفصيلاً وتحديدًا.
لمحة عن مفاتيح المرور
مفاتيح المرور هي بديل أكثر أمانًا وسهولة لكلمات المرور. باستخدام مفاتيح المرور، يمكن للمستخدمين تسجيل الدخول إلى التطبيقات والمواقع الإلكترونية باستخدام أداة استشعار للمقاييس الحيوية (مثل بصمة الإصبع أو التعرّف على الوجوه) أو رقم التعريف الشخصي أو النقش. ويوفّر ذلك تجربة تسجيل دخول سلسة، ما يغني المستخدمين عن تذكُّر أسماء المستخدمين أو كلمات المرور.
تعتمد مفاتيح المرور على WebAuthn (مصادقة الويب)، وهو معيار تم تطويره بشكل مشترك من قِبل تحالف FIDO واتحاد شبكة الويب العالمية (W3C). تستخدم WebAuthn تشفير المفتاح العام لمصادقة المستخدم. يمكن للموقع الإلكتروني أو التطبيق الذي يسجّل المستخدم الدخول إليه عرض المفتاح العام وتخزينه، ولكن لا يمكنه أبدًا عرض المفتاح الخاص. يتم الحفاظ على سرية المفتاح الخاص وأمانه. وبما أنّ المفتاح فريد ومرتبط بالموقع الإلكتروني أو التطبيق، لا يمكن سرقة مفاتيح المرور، ما يوفّر المزيد من الأمان.
يتيح Credential Manager للمستخدمين إنشاء مفاتيح مرور وتخزينها في مدير كلمات المرور في Google.
اطّلِع على مصادقة المستخدم باستخدام مفاتيح المرور للحصول على إرشادات حول كيفية تنفيذ مسارات مصادقة مفاتيح المرور السلسة باستخدام Credential Manager.
المتطلّبات الأساسية
لاستخدام "إدارة بيانات الاعتماد"، أكمِل الخطوات الواردة في هذا القسم.
استخدام إصدار حديث من النظام الأساسي
يتوافق "مدير بيانات الاعتماد" مع الإصدار 4.4 من نظام التشغيل Android (المستوى 19 من واجهة برمجة التطبيقات) والإصدارات الأحدث.
إضافة تبعيات إلى تطبيقك
أضِف التبعيات التالية إلى نص برمجة الإصدار الخاص بوحدة تطبيقك:
implementation(libs.androidx.credentials)
// optional - needed for credentials support from play services, for devices running
// Android 13 and below.
implementation(libs.androidx.credentials.play.services.auth)
مزيد من المعلومات حول كيفية تصغير تطبيقك وإخفاء رموزه البرمجية وتحسينه
إتاحة روابط تنقل إلى مواد عرض رقمية
لتفعيل ميزة مفتاح المرور في تطبيق Android، اربط تطبيقك بموقع إلكتروني تملكه. يمكنك الإفصاح عن هذا الربط من خلال إكمال الخطوات التالية:
أنشئ ملف JSON يتضمّن روابط تنقل إلى مواد عرض رقمية. على سبيل المثال، للإشارة إلى أنّ الموقع الإلكتروني
https://signin.example.com
وتطبيق Android الذي يحمل اسم الحزمةcom.example
يمكنهما مشاركة بيانات اعتماد تسجيل الدخول، أنشئ ملفًا باسمassetlinks.json
يتضمّن المحتوى التالي:[ { "relation" : [ "delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds" ], "target" : { "namespace" : "android_app", "package_name" : "com.example.android", "sha256_cert_fingerprints" : [ SHA_HEX_VALUE ] } } ]
الحقل
relation
هو عبارة عن مصفوفة تتضمّن سلسلة واحدة أو أكثر تصف العلاقة التي يتم الإفصاح عنها. للإشارة إلى أنّ التطبيقات والمواقع الإلكترونية تشارك بيانات اعتماد تسجيل الدخول، حدِّد العلاقات على النحو التالي:delegate_permission/handle_all_urls
وdelegate_permission/common.get_login_creds
.الحقل
target
هو عنصر يحدّد مادة العرض التي ينطبق عليها البيان. تحدّد الحقول التالية موقعًا إلكترونيًا:namespace
web
site
تمثّل هذه السمة عنوان URL للموقع الإلكتروني بالتنسيق
https://domain[:optional_port]
، مثلاًhttps://www.example.com
.يجب أن يكون domain مؤهلاً بالكامل، ويجب حذف optional_port عند استخدام المنفذ 443 لبروتوكول HTTPS.
لا يمكن أن يكون هدف
site
سوى نطاق أساسي، ولا يمكنك قصر ربط التطبيق على دليل فرعي معيّن. لا تضمِّن مسارًا في عنوان URL، مثل شرطة مائلة في النهاية.لا تُعتبر النطاقات الفرعية مطابقة، أي إذا حدّدت domain على أنّه
www.example.com
، لن يكون النطاقwww.counter.example.com
مرتبطًا بتطبيقك.تحدّد الحقول التالية تطبيق Android:
namespace
android_app
package_name
اسم الحزمة المُعلن عنه في بيان التطبيق على سبيل المثال: com.example.android
sha256_cert_fingerprints
بصمات الأصابع SHA256 الخاصة بشهادة التوقيع لتطبيقك استضِف ملف JSON الذي يحتوي على روابط تنقل إلى مواد عرض رقمية في الموقع التالي على نطاق تسجيل الدخول:
https://domain[:optional_port]/.well-known/assetlinks.json
على سبيل المثال، إذا كان نطاق تسجيل الدخول هو
signin.example.com
، استضِف ملف JSON علىhttps://signin.example.com/.well-known/assetlinks.json
.يجب أن يكون نوع MIME لملف "روابط التنقل إلى مواد العرض الرقمية" بتنسيق JSON. تأكَّد من أنّ الخادم يرسل عنوان
Content-Type: application/json
في الردّ.تأكَّد من أنّ المضيف يسمح لـ Google باسترداد ملف Digital Asset Link. إذا كان لديك ملف
robots.txt
، يجب أن يسمح لوكيل Googlebot باسترداد/.well-known/assetlinks.json
. يمكن لمعظم المواقع الإلكترونية السماح لأي وكيل آلي باسترداد الملفات في المسار/.well-known/
كي تتمكّن الخدمات الأخرى من الوصول إلى البيانات الوصفية في تلك الملفات:User-agent: * Allow: /.well-known/
أضِف السطر التالي إلى ملف البيان ضمن
<application>
:<meta-data android:name="asset_statements" android:resource="@string/asset_statements" />
إذا كنت تستخدم ميزة تسجيل الدخول باستخدام كلمة المرور من خلال "إدارة بيانات الاعتماد"، اتّبِع هذه الخطوة لضبط ربط الأصول الرقمية في ملف البيان. هذه الخطوة غير مطلوبة إذا كنت تستخدم مفاتيح المرور فقط.
عليك الإفصاح عن الربط في تطبيق Android، وذلك عن طريق إضافة عنصر يحدّد
assetlinks.json
الملفات التي سيتم تحميلها. يجب إلغاء أي علامات اقتباس أحادية ومزدوجة تستخدمها في السلسلة. مثلاً:<string name="asset_statements" translatable="false"> [{ \"include\": \"https://signin.example.com/.well-known/assetlinks.json\" }] </string>
> GET /.well-known/assetlinks.json HTTP/1.1 > User-Agent: curl/7.35.0 > Host: signin.example.com < HTTP/1.1 200 OK < Content-Type: application/json
ضبط "إدارة بيانات الاعتماد"
لضبط كائن CredentialManager
وتهيئته، أضِف منطقًا مشابهًا لما يلي:
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
تحديد حقول بيانات الاعتماد
في نظام التشغيل Android 14 والإصدارات الأحدث، يمكن استخدام السمة isCredential
للإشارة إلى حقول بيانات الاعتماد، مثل حقول اسم المستخدم أو كلمة المرور. تشير هذه السمة إلى أنّ طريقة العرض هذه هي حقل بيانات اعتماد مخصّص للعمل مع "مدير بيانات الاعتماد" ومزوّدي بيانات الاعتماد التابعين لجهات خارجية، مع المساعدة في تقديم اقتراحات أفضل للملء التلقائي من خلال خدمات الملء التلقائي. عندما يستخدم التطبيق واجهة برمجة التطبيقات Credential Manager، يتم عرض ورقة Credential Manager السفلية التي تتضمّن بيانات الاعتماد المتاحة، ولا تكون هناك حاجة إلى عرض مربّع حوار التعبئة التلقائية الخاص باسم المستخدم أو كلمة المرور. وبالمثل، ليس من الضروري عرض مربّع الحوار الخاص بحفظ ميزة "الملء التلقائي" لكلمات المرور، لأنّ التطبيق سيطلب من Credential Manager API حفظ بيانات الاعتماد.
لاستخدام السمة isCredential
، أضِفها إلى طرق العرض ذات الصلة:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true" />
تسجيل الدخول إلى حساب المستخدم
لاسترداد جميع خيارات مفتاح المرور وكلمة المرور المرتبطة بحساب المستخدم، اتّبِع الخطوات التالية:
-
تهيئة خيارات المصادقة باستخدام كلمة المرور ومفتاح المرور:
// Retrieves the user's saved password for your app from their // password provider. val getPasswordOption = GetPasswordOption() // Get passkey from the user's public key credential provider. val getPublicKeyCredentialOption = GetPublicKeyCredentialOption( requestJson = requestJson )
استخدِم الخيارات التي تم استردادها من الخطوة السابقة لإنشاء طلب تسجيل الدخول.
val credentialRequest = GetCredentialRequest( listOf(getPasswordOption, getPublicKeyCredentialOption), )
ابدأ عملية تسجيل الدخول:
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 } }
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") } } }
يوضّح المثال التالي كيفية تنسيق طلب JSON عند الحصول على مفتاح مرور:
{
"challenge": "T1xCsnxM2DNL2KdK5CLa6fMhD7OBqho6syzInk_n-Uo",
"allowCredentials": [],
"timeout": 1800000,
"userVerification": "required",
"rpId": "https://passkeys-codelab.glitch.me/"
}
يوضّح المثال التالي كيف يمكن أن تبدو استجابة JSON بعد الحصول على بيانات اعتماد المفتاح العام:
{
"id": "KEDetxZcUfinhVi6Za5nZQ",
"type": "public-key",
"rawId": "KEDetxZcUfinhVi6Za5nZQ",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVDF4Q3NueE0yRE5MMktkSzVDTGE2Zk1oRDdPQnFobzZzeXpJbmtfbi1VbyIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
"authenticatorData": "j5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGQdAAAAAA",
"signature": "MEUCIQCO1Cm4SA2xiG5FdKDHCJorueiS04wCsqHhiRDbbgITYAIgMKMFirgC2SSFmxrh7z9PzUqr0bK1HZ6Zn8vZVhETnyQ",
"userHandle": "2HzoHm_hY0CjuEESY9tY6-3SdjmNHOoNqaPDcZGzsr0"
}
}
التعامل مع الاستثناءات عند عدم توفّر بيانات اعتماد
في بعض الحالات، قد لا تتوفّر للمستخدم أي بيانات اعتماد، أو قد لا يمنح المستخدم موافقته على استخدام بيانات اعتماد متوفّرة. إذا تم استدعاء getCredential()
ولم يتم العثور على أي بيانات اعتماد، سيتم عرض NoCredentialException
. في هذه الحالة، يجب أن يتعامل الرمز مع مثيلات NoCredentialException
.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}
على نظام التشغيل Android 14 أو الإصدارات الأحدث، يمكنك تقليل وقت الاستجابة عند عرض أداة اختيار الحساب من خلال استخدام طريقة prepareGetCredential()
قبل استدعاء getCredential()
.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
لا يستدعي الإجراء prepareGetCredential()
عناصر واجهة المستخدم. تساعدك هذه الطريقة فقط في تنفيذ أعمال التحضير حتى تتمكّن لاحقًا من بدء عملية الحصول على بيانات الاعتماد المتبقية (التي تتضمّن واجهات مستخدم) من خلال واجهة برمجة التطبيقات getCredential()
.
يتم عرض البيانات المخزّنة مؤقتًا في عنصر PrepareGetCredentialResponse
. إذا كانت هناك بيانات اعتماد حالية، سيتم تخزين النتائج مؤقتًا، ويمكنك بعد ذلك تشغيل واجهة برمجة التطبيقات المتبقية getCredential()
لاحقًا لعرض أداة اختيار الحساب مع البيانات المخزّنة مؤقتًا.
مسارات التسجيل
يمكنك تسجيل مستخدم للمصادقة باستخدام مفتاح مرور أو كلمة مرور.
إنشاء مفتاح مرور
لمنح المستخدمين خيار تسجيل مفتاح مرور واستخدامه لإعادة المصادقة، سجِّل بيانات اعتماد المستخدم باستخدام عنصر CreatePublicKeyCredentialRequest
.
suspend fun createPasskey(requestJson: String, preferImmediatelyAvailableCredentials: Boolean) {
val createPublicKeyCredentialRequest = CreatePublicKeyCredentialRequest(
// Contains the request in JSON format. Uses the standard WebAuthn
// web JSON spec.
requestJson = requestJson,
// Defines whether you prefer to use only immediately available
// credentials, not hybrid credentials, to fulfill this request.
// This value is false by default.
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials,
)
// Execute CreateCredentialRequest asynchronously to register credentials
// for a user account. Handle success and failure cases with the result and
// exceptions, respectively.
coroutineScope {
try {
val result = credentialManager.createCredential(
// Use an activity-based context to avoid undefined system
// UI launching behavior
context = activityContext,
request = createPublicKeyCredentialRequest,
)
// Handle passkey creation result
} catch (e : CreateCredentialException){
handleFailure(e)
}
}
}
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}")
}
}
تنسيق طلب JSON
بعد إنشاء مفتاح مرور، عليك ربطه بحساب مستخدم وتخزين المفتاح العام لمفتاح المرور على الخادم. يوضّح مثال الرمز البرمجي التالي كيفية تنسيق طلب JSON عند إنشاء مفتاح مرور.
توضّح مشاركة المدونة هذه حول توفير مصادقة سلسة لتطبيقاتك كيفية تنسيق طلب JSON عند إنشاء مفاتيح مرور وعند المصادقة باستخدام مفاتيح المرور. توضّح هذه الصفحة أيضًا لماذا لا تُعدّ كلمات المرور حلاً فعّالاً للمصادقة، وكيفية الاستفادة من بيانات الاعتماد الحالية المستندة إلى المقاييس الحيوية، وكيفية ربط تطبيقك بموقع إلكتروني تملكه، وكيفية إنشاء مفاتيح مرور، وكيفية المصادقة باستخدام مفاتيح المرور.
{
"challenge": "abc123",
"rp": {
"name": "Credential Manager example",
"id": "credential-manager-test.example.com"
},
"user": {
"id": "def456",
"name": "helloandroid@gmail.com",
"displayName": "helloandroid@gmail.com"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -257
}
],
"timeout": 1800000,
"attestation": "none",
"excludeCredentials": [
{
"id": "ghi789",
"type": "public-key"
},
{
"id": "jkl012",
"type": "public-key"
}
],
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
ضبط قيم authenticatorAttachment
لا يمكن ضبط المَعلمة authenticatorAttachment
إلا عند إنشاء بيانات الاعتماد. يمكنك تحديد platform
أو cross-platform
أو عدم تحديد أي قيمة. في معظم الحالات،
لا يُنصح بإدخال أي قيمة.
platform
: لتسجيل الجهاز الحالي للمستخدم أو مطالبة المستخدم بكلمة مرور لترقية حسابه إلى مفاتيح مرور بعد تسجيل الدخول، اضبطauthenticatorAttachment
علىplatform
.cross-platform
: تُستخدَم هذه القيمة عادةً عند تسجيل بيانات اعتماد مصادقة متعدّدة العوامل، ولا تُستخدَم في سياق مفتاح المرور.- بدون قيمة: لمنح المستخدمين المرونة في إنشاء مفاتيح مرور على أجهزتهم المفضّلة (مثل إعدادات الحساب)، يجب عدم تحديد المَعلمة
authenticatorAttachment
عندما يختار المستخدم إضافة مفتاح مرور. في معظم الحالات، يكون عدم تحديد المعلمة هو الخيار الأفضل.
منع إنشاء مفاتيح مرور مكرّرة
أدرِج معرّفات بيانات الاعتماد في مصفوفة excludeCredentials
الاختيارية لمنع إنشاء مفتاح مرور جديد إذا كان هناك مفتاح مرور حالي لدى مقدّم خدمة مفاتيح المرور نفسه.
التعامل مع استجابة JSON
يوضّح مقتطف الرمز التالي مثالاً على استجابة JSON لإنشاء بيانات اعتماد مفتاح عام. مزيد من المعلومات حول كيفية التعامل مع بيانات اعتماد المفتاح العام الذي تم إرجاعه
{
"id": "KEDetxZcUfinhVi6Za5nZQ",
"type": "public-key",
"rawId": "KEDetxZcUfinhVi6Za5nZQ",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibmhrUVhmRTU5SmI5N1Z5eU5Ka3ZEaVh1Y01Fdmx0ZHV2Y3JEbUdyT0RIWSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOk1MTHpEdll4UTRFS1R3QzZVNlpWVnJGUXRIOEdjVi0xZDQ0NEZLOUh2YUkiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20uZ29vZ2xlLmNyZWRlbnRpYWxtYW5hZ2VyLnNhbXBsZSJ9",
"attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUj5r_fLFhV-qdmGEwiukwD5E_5ama9g0hzXgN8thcFGRdAAAAAAAAAAAAAAAAAAAAAAAAAAAAEChA3rcWXFH4p4VYumWuZ2WlAQIDJiABIVgg4RqZaJyaC24Pf4tT-8ONIZ5_Elddf3dNotGOx81jj3siWCAWXS6Lz70hvC2g8hwoLllOwlsbYatNkO2uYFO-eJID6A"
}
}
التحقّق من المصدر من ملف JSON لبيانات العميل
يمثّل origin
التطبيق أو الموقع الإلكتروني الذي يأتي منه الطلب، وتستخدمه مفاتيح المرور للحماية من هجمات التصيّد الاحتيالي.
يجب أن يتحقّق خادم تطبيقك من مصدر بيانات العميل مقارنةً بقائمة السماح التي تضم التطبيقات والمواقع الإلكترونية المعتمَدة. إذا تلقّى الخادم طلبًا من تطبيق أو موقع إلكتروني من مصدر غير معروف، يجب رفض الطلب.
في حالة الويب، يعرض origin
المصدر نفسه الذي تم فيه تسجيل الدخول باستخدام بيانات الاعتماد. على سبيل المثال، إذا كان عنوان URL هو
https://www.example.com:8443/store?category=shoes#athletic
، فإنّ origin
هو
https://www.example.com:8443
.
بالنسبة إلى تطبيقات Android، يضبط وكيل المستخدم تلقائيًا قيمة origin
على توقيع التطبيق الذي يطلب البيانات. يجب التحقّق من تطابق هذا التوقيع على الخادم للتحقّق من صحة هوية طالب بيانات واجهة برمجة التطبيقات الخاصة بمفاتيح المرور. origin
Android هو معرّف URI مشتق
من تجزئة SHA-256 لشهادة توقيع حزمة APK، مثل:
android:apk-key-hash:<sha256_hash-of-apk-signing-cert>
يمكن العثور على تجزئات SHA-256 لشهادات التوقيع من ملف تخزين المفاتيح من خلال تنفيذ أمر الوحدة الطرفية التالي:
keytool -list -keystore <path-to-apk-signing-keystore>
تكون تجزئات SHA-256 بتنسيق سداسي عشري مفصول بنقطتين رأسيتين (91:F7:CB:F9:D6:81…
)، وتكون قيم origin
في Android بترميز base64url.
يوضّح مثال Python التالي كيفية تحويل تنسيق التجزئة إلى تنسيق سداسي عشري متوافق ومفصول بنقطتين رأسيتين:
import binascii
import base64
fingerprint = '91:F7:CB:F9:D6:81:53:1B:C7:A5:8F:B8:33:CC:A1:4D:AB:ED:E5:09:C5'
print("android:apk-key-hash:" + base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
استبدِل قيمة fingerprint
بقيمتك الخاصة. في ما يلي مثال على النتيجة:
android:apk-key-hash:kffL-daBUxvHpY-4M8yhTavt5QnFEI2LsexohxrGPYU
يمكنك بعد ذلك مطابقة هذه السلسلة كمصدر مسموح به على خادمك. إذا كانت لديك شهادات توقيع متعددة، مثل شهادات تصحيح الأخطاء وإصدار التطبيق، أو تطبيقات متعددة، كرِّر العملية واقبل جميع المصادر على أنّها صالحة على الخادم.
حفظ كلمة مرور مستخدم
إذا قدّم المستخدم اسم مستخدم وكلمة مرور لتنفيذ عملية مصادقة في تطبيقك، يمكنك تسجيل بيانات اعتماد مستخدم يمكن استخدامها لمصادقة المستخدم. لإجراء ذلك، أنشئ عنصر CreatePasswordRequest
:
suspend fun registerPassword(username: String, password: String) {
// Initialize a CreatePasswordRequest object.
val createPasswordRequest =
CreatePasswordRequest(id = username, password = password)
// Create credential and handle result.
coroutineScope {
try {
val result =
credentialManager.createCredential(
// Use an activity based context to avoid undefined
// system UI launching behavior.
activityContext,
createPasswordRequest
)
// Handle register password result
} catch (e: CreateCredentialException) {
handleFailure(e)
}
}
}
استرداد بيانات الاعتماد
إذا لم يعُد بإمكان المستخدم الوصول إلى جهاز كان قد خزّن فيه بيانات الاعتماد، قد يحتاج إلى استعادة البيانات من نسخة احتياطية آمنة على الإنترنت. لمزيد من المعلومات حول كيفية إتاحة عملية استرداد بيانات الاعتماد هذه، يمكنك الاطّلاع على القسم بعنوان "استرداد إذن الوصول أو إضافة أجهزة جديدة" في مشاركة المدونة هذه: أمان مفاتيح المرور في "مدير كلمات المرور" من Google.
إنشاء مفاتيح مرور للمستخدمين تلقائيًا
إذا لم يكن لدى المستخدم مفتاح مرور، يمكنك إنشاء مفتاح مرور تلقائيًا نيابةً عنه في المرة التالية التي يسجّل فيها الدخول باستخدام كلمة مرور محفوظة في خدمة إدارة كلمات المرور. يمكنك إجراء ذلك من خلال ضبط الحقل isConditionalCreateRequest
عند طلب بيانات اعتماد عامة:
CreatePublicKeyCredentialRequest(
// other parameters
isConditionalCreateRequest: Boolean = true
)
عندما يسجّل المستخدم الدخول، يتم إنشاء مفتاح مرور تلقائيًا وتخزينه في خدمة إدارة كلمات المرور التي يختارها. في حال استخدام "مدير كلمات المرور في Google"، يجب أن يكون المستخدم قد استخدم كلمة المرور المحفوظة في خدمة إدارة كلمات المرور (إما باستخدام Credential Manager أو ميزة "الملء التلقائي"). سيتلقّى المستخدم إشعارًا عند إنشاء مفتاح المرور هذا، وسيتمكّن من الانتقال إلى مدير كلمات المرور لإدارته.
تتطلّب هذه الميزة الإصدار 1.6.0-alpha01 أو إصدارًا أحدث.
إتاحة استخدام أدوات إدارة كلمات المرور مع عناوين URL المعروفة لنقاط نهاية مفتاح المرور
لضمان التكامل السلس والتوافق المستقبلي مع أدوات إدارة كلمات المرور وبيانات الاعتماد، ننصحك بإتاحة عناوين URL المعروفة لنقاط نهاية مفاتيح المرور. هذا بروتوكول مفتوح للأطراف المعنية للإعلان رسميًا عن إتاحة مفاتيح المرور وتقديم روابط مباشرة لتسجيل مفاتيح المرور وإدارتها.
- بالنسبة إلى جهة معتمدة على
https://example.com
، والتي لديها موقع إلكتروني بالإضافة إلى تطبيقات Android وiOS، سيكون عنوان URL المعروف هوhttps://example.com/.well-known/passkey-endpoints
. عند الاستعلام عن عنوان URL، يجب أن تستخدم الاستجابة المخطط التالي
{ "enroll": "https://example.com/account/manage/passkeys/create" "manage": "https://example.com/account/manage/passkeys" }
لفتح هذا الرابط مباشرةً في تطبيقك بدلاً من فتحه على الويب، استخدِم روابط تطبيقات Android.
يمكنك الاطّلاع على مزيد من التفاصيل في شرح حول عنوان URL المعروف لنقاط نهاية مفتاح المرور على GitHub.
مساعدة المستخدمين في إدارة مفاتيح المرور من خلال توضيح الجهة التي أنشأتها
أحد التحديات التي يواجهها المستخدمون عند إدارة مفاتيح مرور متعددة مرتبطة بتطبيق معيّن هو تحديد مفتاح المرور الصحيح لتعديله أو حذفه. للمساعدة في حلّ هذه المشكلة، ننصح التطبيقات والمواقع الإلكترونية بتضمين معلومات إضافية، مثل مقدّم الخدمة الذي أنشأ بيانات الاعتماد وتاريخ الإنشاء وتاريخ آخر استخدام، في قائمة مفاتيح المرور ضمن شاشة إعدادات التطبيق.يتم الحصول على معلومات مقدّم الخدمة من خلال فحص AAGUID المرتبط بمفتاح المرور المعنيّ. يمكن العثور على AAGUID كجزء من بيانات المصادقة الخاصة بمفتاح المرور.
على سبيل المثال، إذا أنشأ مستخدم مفتاح مرور على جهاز يعمل بنظام التشغيل Android باستخدام "مدير كلمات المرور من Google"، سيتلقّى الطرف المعتمد بعد ذلك معرّف AAGUID يشبه ما يلي: "ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4". يمكن للجهة المعتمِدة إضافة تعليق توضيحي إلى مفتاح المرور في قائمة مفاتيح المرور للإشارة إلى أنّه تم إنشاؤه باستخدام "مدير كلمات المرور في Google".
لربط AAGUID بمقدّم مفاتيح المرور، يمكن للأطراف المعتمِدة استخدام مستودع AAGUID مستند إلى المصادر المجتمعية. ابحث عن AAGUID في القائمة للعثور على اسم مزوّد مفتاح المرور ورمزه.
مزيد من المعلومات عن دمج AAGUID
تحديد المشاكل الشائعة وحلّها
راجِع دليل تحديد المشاكل وحلّها في Credential Manager للاطّلاع على رموز الأخطاء الشائعة وأوصافها ومعلومات حول أسبابها.
مراجع إضافية
لمزيد من المعلومات حول واجهة برمجة التطبيقات Credential Manager ومفاتيح المرور، اطّلِع على المراجع التالية:
- دليل تجربة المستخدم بشأن مفاتيح المرور
- فيديو: كيفية تقليل الاعتماد على كلمات المرور في تطبيقات Android من خلال توفير ميزة مفتاح المرور
- درس تطبيقي: تعرَّف على كيفية تبسيط رحلات المصادقة باستخدام Credential Manager API في تطبيق Android
- تطبيق نموذجي: CredentialManager