ایجاد شرطی گذرکلید (تبلیغ پس‌از ورود به سیستم)

این راهنما به‌طور دقیق توضیح می‌دهد که چگونه می‌توان بلافاصله پس‌از ورود موفقیت‌آمیز به سیستم با گذرواژه، گذرکلیدی را به‌طور خودکار و بی‌صدا برای کاربر ثبت کرد تا اصطکاک به حداقل برسد و پذیرش گذرکلید افزایش یابد.

لحظه راه‌انداز مناسب

ایجاد خودکار گذرکلید (که با نام «ایجاد مشروط» یا «تبلیغ بی‌صدا پس‌از ورود به سیستم» نیز شناخته می‌شود) باید فقط بلافاصله پس‌از ورود به سیستم کامل و موفقیت‌آمیز که شامل گذرواژه بوده است راه‌اندازی شود.

  • برای جریان‌های بدون گذرواژه (مثلاً پیوندهای جادویی، گذرواژه یک‌بارمصرف پیامکی، یا فدراسیون هویت) ایجاد شرطی را امتحان نکنید.
  • اگر اصالت‌سنجی چندعاملی لازم است، باید منتظر بمانید تا همه عوامل با موفقیت انجام شوند و سپس ایجاد شرطی را آغاز کنید.
  • قبل‌از درخواست دادن به نقاط پایانی ایجاد، مطمئن شوید که جلسه کاربر معتبر و اصالت‌سنجی‌شده فعال باشد.

مراحل پیاده‌سازی

۱. لغو کردن کنش‌های تکمیل خودکار قبلی

اگر صفحه ورود به سیستم از تکمیل خودکار فرم (رابط کاربری شرطی/دریافت) استفاده می‌کند، فراخوانی دریافت اطلاعات اعتباری فعال باید لغو شود تا از تداخل مرورگر جلوگیری شود.

  • قبل‌از تماس با navigator.credentials.create()، با abortController.abort() در AbortController پیوست‌شده به درخواست تکمیل خودکار navigator.credentials.get() معلقه تماس بگیرید.

۲. تشخیص ویژگی

با بررسی conditionalCreate با PublicKeyCredential.getClientCapabilities()، تعیین کنید که آیا «ایجاد شرطی» دردسترس است یا نه.

const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
  // Conditional create is available
}

۳. ایجاد گذرکلید با «ایجاد شرطی»

  • ‫mediation: 'conditional' را در گزینه‌های navigator.credentials.create() رد کنید. این به مرورگر علامت می‌دهد که جریان ایجاد گذرکلید را به‌طور بی‌صدا در پس‌زمینه یا به‌صورت زمینه‌ای بدون نمایش کادرهای گفتگوی مدال مزاحم مدیریت کند.
  • excludeCredentials را با شناسه‌های اعتبارنامه گذرکلید موجود کاربر پر کنید تا از ثبت کلیدهای تکراری جلوگیری شود.

۴. مدیریت کردن خطای بی‌صدا

  • پیام‌واره ایجاد گذرکلید (navigator.credentials.create) را در یک بلوک try/catch قرار دهید. باید استثناهای معمول سَمت کاربر (InvalidStateError، NotAllowedError، AbortError) را بگیرید و بدون ارائه هیچ‌گونه میانای کاربر خطا به کاربر، آن‌ها را نادیده بگیرید.

۵. درستی‌سنجی حضور کاربر در سمت سرور

  • نقطه پایانی درستی‌سنجی سمت سرور باید الزام «حضور کاربر» (UP) را (requireUserPresence: false) فقط هنگام درستی‌سنجی اطلاعات اعتباری تولیدشده توسط راه‌انداز ایجاد شرطی کاهش دهد. درستی‌سنجی حضور سخت‌گیرانه باید برای ایجاد محتوای صریح استاندارد فعال بماند.

‫۶. رسیدگی به تأیید ناموفق سرور به‌صورت مناسب

  • اگر 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';