على الرغم من أنّ بيانات اعتماد FIDO، مثل مفاتيح المرور، تهدف إلى استبدال كلمات المرور، يمكن لمعظمها أيضًا إعفاء المستخدم من كتابة اسم المستخدم. يتيح ذلك للمستخدمين المصادقة من خلال اختيار حساب من قائمة مفاتيح المرور التي لديهم للموقع الإلكتروني الحالي.
تم تصميم الإصدارات السابقة من مفاتيح الأمان كطرق مصادقة بخطوتين، وكانت تتطلّب معرّفات بيانات الاعتماد المحتملة، وبالتالي تتطلّب إدخال اسم مستخدم. تُعرف بيانات الاعتماد التي يمكن لمفتاح الأمان العثور عليها بدون معرفة معرّفاتها باسم بيانات الاعتماد القابلة للاكتشاف. معظم بيانات اعتماد FIDO التي يتم إنشاؤها اليوم هي بيانات اعتماد قابلة للاكتشاف، لا سيما مفاتيح المرور المخزَّنة في مدير كلمات المرور أو على مفتاح أمان حديث.
لضمان إنشاء بيانات الاعتماد كمفاتيح مرور (بيانات اعتماد قابلة للاكتشاف)، حدِّد residentKey وrequireResidentKey عند إنشاء بيانات الاعتماد.
يمكن للأطراف المعتمِدة (RP) استخدام بيانات الاعتماد القابلة للاكتشاف من خلال حذف
allowCredentials أثناء المصادقة باستخدام مفتاح المرور. في هذه الحالات،
يعرض المتصفّح أو النظام للمستخدم قائمة بمفاتيح المرور المتاحة، والتي يتم تحديدها من خلال
السمة user.name التي تم ضبطها في وقت الإنشاء. إذا اختار المستخدم أحدها، سيتم تضمين قيمة user.id في التوقيع الناتج. يمكن للخادم بعد ذلك استخدام رقم تعريف بيانات الاعتماد الذي تم عرضه للبحث عن الحساب بدلاً من اسم المستخدم المكتوب.
لا تعرض واجهات المستخدم الخاصة بأداة اختيار الحسابات، مثل تلك التي تمت مناقشتها سابقًا، بيانات الاعتماد غير القابلة للاكتشاف.
requireResidentKey وresidentKey
لإنشاء مفتاح مرور، حدِّد authenticatorSelection.residentKey وauthenticatorSelection.requireResidentKey في navigator.credentials.create() باستخدام القيم الموضّحة على النحو التالي.
async function register () {
// ...
const publicKeyCredentialCreationOptions = {
// ...
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
requireResidentKey: true,
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
residentKey:
-
'required': يجب إنشاء بيانات اعتماد قابلة للاكتشاف. وإذا تعذّر إنشاؤه، يتم عرضNotSupportedError. -
'preferred': يفضّل الطرف المعتمِد إنشاء بيانات اعتماد قابلة للاكتشاف، ولكنّه يقبل بيانات الاعتماد غير القابلة للاكتشاف. -
'discouraged': يفضّل الطرف المعتمِد إنشاء بيانات اعتماد غير قابلة للاكتشاف، ولكنّه يقبل بيانات الاعتماد القابلة للاكتشاف.
requireResidentKey:
- يتم الاحتفاظ بهذه السمة للتوافق مع الأنظمة القديمة من WebAuthn Level 1، وهو إصدار قديم من المواصفات. اضبط هذه السمة على
trueإذا كانت قيمةresidentKeyهي'required'، وإلا اضبطها علىfalse.
allowCredentials
يمكن للجهات المعتمِدة استخدام allowCredentials على navigator.credentials.get() للتحكّم في تجربة المصادقة باستخدام مفتاح المرور. هناك عادةً ثلاثة أنواع من تجارب المصادقة باستخدام مفاتيح المرور:
عرض أداة اختيار الحساب في نافذة مشروطة
باستخدام بيانات الاعتماد القابلة للاكتشاف، يمكن للجهات المعتمِدة عرض أداة اختيار حساب مشروطة للمستخدم لاختيار حساب لتسجيل الدخول به، متبوعةً بعملية تأكيد هوية المستخدم. هذا الإجراء مناسب لعملية مصادقة مفتاح المرور التي تبدأ بالضغط على زر مخصّص لمصادقة مفتاح المرور.
لتحقيق تجربة المستخدم هذه، يمكنك حذف مصفوفة فارغة أو تمريرها إلى المَعلمة allowCredentials في navigator.credentials.get().
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
عرض نموذج ملء تلقائي لمفتاح مرور
يعمل محدّد الحسابات المشروط الموضّح أعلاه بشكل جيد إذا كان معظم المستخدمين يستخدمون مفاتيح المرور وتتوفّر لديهم على الجهاز المحلي. بالنسبة إلى المستخدم الذي ليس لديه مفاتيح مرور محلية، سيظل مربّع الحوار المشروط يظهر وسيعرض على المستخدم تقديم مفتاح مرور من جهاز آخر. أثناء نقل المستخدمين إلى مفاتيح المرور، قد تحتاج إلى تجنُّب واجهة المستخدم هذه للمستخدمين الذين لم يضبطوا مفتاح مرور.
بدلاً من ذلك، قد يتم دمج اختيار مفتاح مرور في طلبات الملء التلقائي للحقول في نموذج تسجيل الدخول التقليدي، إلى جانب أسماء المستخدمين وكلمات المرور المحفوظة. بهذه الطريقة، يمكن للمستخدم الذي لديه مفاتيح مرور "ملء" نموذج تسجيل الدخول من خلال اختيار مفتاح المرور الخاص به، ويمكن للمستخدمين الذين لديهم أزواج من أسماء المستخدمين وكلمات المرور المحفوظة اختيارها، ويمكن للمستخدمين الذين ليس لديهم أيّ منهما كتابة اسم المستخدم وكلمة المرور.
تُعدّ تجربة المستخدم هذه مثالية عندما يكون الطرف المعتمِد في مرحلة نقل البيانات مع استخدام مختلط لكلمات المرور ومفاتيح المرور.
لتحقيق تجربة المستخدم هذه، بالإضافة إلى تمرير مصفوفة فارغة إلى السمة allowCredentials أو حذف المَعلمة، حدِّد mediation: 'conditional' في navigator.credentials.get() وأضِف تعليقًا توضيحيًا إلى حقل إدخال HTML username باستخدام autocomplete="username webauthn" أو حقل إدخال password باستخدام autocomplete="password webauthn".
لن يؤدي طلب navigator.credentials.get() إلى عرض أي واجهة مستخدم، ولكن إذا ركّز المستخدم على حقل الإدخال الذي يتضمّن تعليقات توضيحية، سيتم تضمين أي مفاتيح مرور متاحة في خيارات الملء التلقائي. إذا اختار المستخدم أحد الخيارات، سيتم إجراء عملية التحقّق العادية لفتح قفل الجهاز، وبعد ذلك فقط سيتم حلّ الوعد الذي يعرضه .get() مع نتيجة. إذا لم يختَر المستخدم مفتاح مرور، لن يتم حلّ الوعد أبدًا.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const cred = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
<input type="text" name="username" autocomplete=&qu>ot;username webauthn" ...
يمكنك التعرّف على كيفية إنشاء تجربة المستخدم هذه في مقالة تسجيل الدخول باستخدام مفتاح مرور من خلال ميزة الملء التلقائي للنموذج، بالإضافة إلى الدرس التطبيقي حول الترميز تسجيل الدخول باستخدام مفاتيح المرور من خلال ميزة الملء التلقائي للنموذج في تطبيق الويب.
إعادة المصادقة
في بعض الحالات، مثل استخدام مفاتيح المرور لإعادة المصادقة، يكون معرّف المستخدم معروفًا من قبل. في هذه الحالة، نريد استخدام مفتاح مرور بدون أن يعرض المتصفّح أو نظام التشغيل أي شكل من أشكال أداة اختيار الحساب. ويمكن إجراء ذلك من خلال تمرير قائمة بأرقام تعريف بيانات الاعتماد في المَعلمة allowCredentials.
في هذه الحالة، إذا كانت أي من بيانات الاعتماد المحدّدة متاحة على الجهاز، سيُطلب من المستخدم فتح قفل الجهاز على الفور. وإذا لم يكن الأمر كذلك، سيُطلب من المستخدم تقديم جهاز آخر (هاتف أو مفتاح أمان) يحتوي على بيانات اعتماد صالحة.
لتحقيق تجربة المستخدم هذه، قدِّم قائمة بأرقام تعريف بيانات الاعتماد للمستخدم الذي يسجّل الدخول. يجب أن يتمكّن الطرف المعتمد من طلبها لأنّ المستخدم معروف مسبقًا. قدِّم معرّفات بيانات الاعتماد كعناصر PublicKeyCredentialDescriptor في السمة allowCredentials في navigator.credentials.get().
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// Provide a list of PublicKeyCredentialDescriptors:
allowCredentials: [{
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, {
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, ...]
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
يتكوّن عنصر PublicKeyCredentialDescriptor من:
-
id: معرّف بيانات اعتماد المفتاح العام الذي حصلت عليه الجهة المحظورة عند تسجيل مفتاح المرور. -
type: يكون هذا الحقل عادةً'public-key'. -
transports: تلميح حول وسائل النقل التي يتيحها الجهاز الذي يحمل بيانات الاعتماد هذه، وتستخدمه المتصفّحات لتحسين واجهة المستخدم التي تطلب من المستخدم تقديم جهاز خارجي. يجب أن تحتوي هذه القائمة، في حال توفّرها، على نتيجة طلبgetTransports()أثناء تسجيل كل بيانات اعتماد.
ملخّص
تسهّل بيانات الاعتماد القابلة للاكتشاف تجربة تسجيل الدخول باستخدام مفتاح المرور من خلال السماح للمستخدمين بتخطّي إدخال اسم المستخدم. من خلال الجمع بين residentKey وrequireResidentKey وallowCredentials، يمكن للجهات المعتمِدة تحقيق تجارب تسجيل دخول:
- عرض أداة اختيار الحسابات في نافذة مشروطة
- عرض نموذج ملء تلقائي لمفتاح المرور
- إعادة المصادقة:
استخدِم بيانات الاعتماد القابلة للاكتشاف بحكمة. من خلال إجراء ذلك، يمكنك تصميم تجارب تسجيل دخول متطوّرة باستخدام مفاتيح المرور، ما يوفّر للمستخدمين تجربة سلسة ويزيد من احتمالية تفاعلهم معها.