במדריך הזה מוסבר איך לרשום מפתח גישה למשתמש באופן אוטומטי ושקט מיד אחרי כניסה מוצלחת באמצעות סיסמה, כדי לצמצם את החיכוך ולעודד את השימוש במפתחות גישה.
הרגע הנכון להפעלת המודעה
יצירה אוטומטית של מפתחות גישה (שנקראת גם "יצירה מותנית" או "קידום שקט אחרי כניסה") חייבת להתבצע מיד אחרי כניסה מלאה ומוצלחת באמצעות סיסמה.
- אל תנסו ליצור תהליכים מותנים ללא סיסמה (למשל, קישורים חד-פעמיים לכניסה, סיסמאות חד-פעמיות ב-SMS או איחוד זהויות).
- אם נדרש אימות רב-שלבי, צריך לחכות עד שכל השלבים יושלמו בהצלחה לפני שמתחילים ליצור את התנאי.
- לפני ששולחים בקשות לנקודות קצה ליצירה, צריך לוודא שסשן המשתמש המאומת תקין ופעיל.
שלבי ההטמעה
1. ביטול פעולות קודמות של מילוי אוטומטי
אם דף הכניסה משתמש במילוי אוטומטי של טפסים (ממשק משתמש מותנה/Get), צריך לבטל את הקריאה הפעילה לקבלת פרטי הכניסה כדי למנוע התנגשויות בדפדפן.
- צריך להתקשר אל
abortController.abort()ב-AbortControllerשמצורף לבקשת המילוי האוטומטי שלnavigator.credentials.get()בהמתנה לפני שמתקשרים אלnavigator.credentials.create().
2. זיהוי תכונות
כדי לבדוק אם אפשר להשתמש ביצירה מותנית, בודקים את conditionalCreate באמצעות PublicKeyCredential.getClientCapabilities().
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
// Conditional create is available
}
3. יצירת מפתח גישה באמצעות Conditional Create
- מעבירים את הערך
mediation: 'conditional'באפשרויות שלnavigator.credentials.create(). כך הדפדפן מקבל הוראה לטפל בתהליך יצירת מפתח הגישה באופן שקט ברקע או בהתאם להקשר, בלי להציג תיבות דו-שיח מודאליות פולשניות. - כדי למנוע רישום של מפתחות כפולים, מאכלסים את
excludeCredentialsבמזהי פרטי הכניסה הקיימים של מפתחות הגישה של המשתמש.
4. טיפול בשגיאות שקטות
- עוטפים את ההנחיה ליצירת מפתח הגישה (
navigator.credentials.create) בבלוק try/catch. חובה לתפוס חריגות אופייניות שגלויות למשתמשים (InvalidStateError,NotAllowedError,AbortError) ולהתעלם מהן בלי להציג למשתמש ממשק משתמש של שגיאה.
5. אימות נוכחות משתמש בצד השרת
- נקודת הקצה לאימות בצד השרת חייבת להקל על הדרישה לנוכחות משתמש (UP) (
requireUserPresence: false) רק כשמאמתים פרטי כניסה שנוצרו על ידי טריגר ליצירה מותנית. אימות נוכחות קפדני חייב להישאר פעיל ביצירות רגילות של תוכן בוטה.
6. טיפול באימות שרת שנכשל
- אם
navigator.credentials.create()מצליח אבל אחזור האימות של השרת מחזיר תגובה לא תקינה (למשל, אימות החתימה נכשל), צריך להפעיל אתPublicKeyCredential.signalUnknownCredential()כדי למנוע מפרטי כניסה מיותרים להישאר אצל ספק מפתחות הגישה.
קוד לדוגמה
// optionsFetch and registerVerifyFetch are app-defined server endpoint requests
import { optionsFetch, registerVerifyFetch } from './api.js';
async function triggerConditionalCreate(loginAbortController) {
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate !== true) {
return; // Platform does not support conditional creation
}
// 1. Abort any active autofill conditional-get controllers to clear the WebAuthn pipeline
loginAbortController.abort();
// 2. Fetch creation options signaling the backend that this is a conditional request
const creationOptionsJSON = await optionsFetch({ conditional: true });
const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(creationOptionsJSON);
let credential;
try {
// 3. Invoke silent credentials creation prompt
credential = await navigator.credentials.create({
publicKey,
mediation: 'conditional' // Silent background creation mediation
});
} catch (e) {
// 4. Silently swallow common WebAuthn browser exceptions
if (['InvalidStateError', 'NotAllowedError', 'AbortError'].includes(e.name)) {
return;
}
console.error('Unexpected conditional create error:', e);
return;
}
// 5. Server verification step using dedicated Try/Catch block
let encodedResponse = credential.toJSON();
try {
const response = await registerVerifyFetch(encodedResponse);
if (!response.ok) {
// If the server verification fails, clean up using Signal API
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id
});
}
}
} catch (serverErr) {
console.error('Verification network failure:', serverErr);
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id
});
}
}
}
שיטות חלופיות
זיהוי תכונות של מפתחות גישה – חלופה
תמיד צריך להתקין את webauthn-polyfills ולייבא אותו בהקשר.
כל עוד יש תמיכה ב-PublicKeyCredential, יש תמיכה גם ב-PublicKeyCredential.getClientCapabilities.
import 'webauthn-polyfills';
חלופה לסנכרון של Signal API
WebAuthn Signal API (webauthn-signals) הוא אופטימיזציה מתקדמת שמשמשת לסנכרון של מנהלי הסיסמאות עם מצב פרטי הכניסה בשרת.
- תהליך לגיבוי: מוגבל באמצעות
if (PublicKeyCredential.signalUnknownCredential). אם אין תמיכה, המערכת תעקוף את סנכרון האימות ברקע בלי להציג חריגות בדפדפן.
Easy JSON Serialization Fallback
תמיד צריך להתקין את webauthn-polyfills ולייבא אותו בהקשר.
כל עוד יש תמיכה ב-PublicKeyCredential, יש תמיכה גם ב-PublicKeyCredential.parseCreationOptionsFromJSON וב-PublicKeyCredential.prototype.toJSON.
import 'webauthn-polyfills';