این راهنما جزئیات نحوه پیادهسازی اصالتسنجی کاربر بازگشتی را بااستفاده از اطلاعات کاربری قابلکشف، هم ازطریق راهاندازهای دکمه صریح و هم ازطریق پیشنهادهای تکمیل خودکار مرورگر یکپارچه (رابط کاربری شرطی)، شرح میدهد.
سمت سرور
تولید کردن گزینهها
نقطه پایانیای ایجاد کنید که پارامترهای درخواست WebAuthn را بااستفاده از کتابخانه تأییدشده طبق استانداردها تولید کند.
- استفاده از شناسه RP ازپیشتعریفشده: از شناسه RP مناسب ازپیشتعریفشده بهعنوان رشته ثابت استفاده کنید.
- تولید چالش: یک میانگیر تصادفی با آنتروپی بالا و ازنظر رمزنگاری ایمن تولید کنید، آن را بهطور ایمن در جلسه کاربر ذخیره کنید، و آن را بهعنوان Base64URL کدبندی کنید.
- نگاشت «اعتبارنامههای قابلکشف»: آرایه خالی
[]را برایallowCredentialsمشخص کنید. این درخواست اعتبارنامههای قابلکشف را میطلبد، به این معنی که کاربر نیازی به وارد کردن نام کاربری خود در ابتدا ندارد؛ ارائهدهنده گذرکلید حسابهای موجود را ارائه خواهد داد. - سطح درستیسنجی کاربر:
userVerification: "preferred"را تنظیم کنید (یا"required"را اگر صریحاً توسط خطمشیهای رعایت مقررات شرکتی الزامی شده است).- سطح محدودیت
userVerificationدرخواستشده باید در سابقه جلسه سرور در نقطه پایانی گزینهها حفظ شود، نه اینکه ازطریق رشتههای پُرسمان از کارخواه برگردانده شود. این کار به نقطه پایانی درستیسنجی اجازه میدهد تا محدودیتهای تطابق دقیق را بهطور ایمن و بدون خطر دستکاری مشتری اعمال کند.
- سطح محدودیت
// Options generation example (discoverable flow)
const options = {
challenge: serverGeneratedBase64UrlChallenge, // High-entropy random challenge stored in session
rpId: "example.com",
allowCredentials: [], // Request discoverable passkeys
userVerification: "preferred",
};
// Persist expected UV level to user session
req.session.expectedUserVerification = "preferred";
نقطه پایان درستیسنجی
برای اصالتسنجی کاربر، ادعای برگرداندهشده توسط کارخواه را بهطور ایمن درستیسنجی کنید:
- اعتبارسنجی چالش جلسه: مطابقت دقیق چالش بین پاسخ کارخواه و چالش موردانتظار ذخیرهشده در جلسه را اعمال کنید.
- اجرای اولویتهای UV:
- اگر جلسه
expectedUserVerificationدرخواست شده است"preferred"، با ارسالrequireUserVerification: falseبه کتابخانه درستیسنجی سمت سرور، به اصالتسنجهای بدون UV (مثلاً قفلهای صفحه اصالتسنج غیرفعالشده) اجازه دهید. درصورت درخواست"required"، وارد کردن پین/ زیستسنجشی را بهطور جدی اعمال کنید.
- اگر جلسه
- خطای سرور Clean 404: اگر شناسه اطلاعات کاربری برگرداندهشده توسط کارخواه در پایگاه داده پیدا نشد، خطای صریح HTTP
404را برگردانید تا کارخواه بتواند Signal API را راهاندازی کند.
منطق سمت کارخواه
HTML Form Annotation
ورودیهای نام کاربری و گذرواژه را حاشیهنویسی کنید تا بهطور بومی از «میانای کاربری شرطی» بهره ببرید. نشانهای تکمیل خودکار پارامترهای مشخصات webauthn را ترکیب میکنند و فوکوس خودکار باعث میشود وقتی ورودی فوکوس میشود، بالاپر تکمیل خودکار مرورگر فوراً فعال شود.
<!-- Autocomplete tokens must contain webauthn space-separated -->
<form id="signin-form">
<input
type="text"
name="username"
autocomplete="username webauthn"
autofocus
data-testid="username-field"
/>
<input type="password" name="password" autocomplete="current-password" />
<button type="submit">Sign in</button>
</form>
جریان دکمه صریح
وقتی کاربر روی دکمه «ورود به سیستم با گذرکلید» کلیک میکند، اصالتسنجی با گذرکلید را راهاندازی کنید. قبلاز فراخوانی درخواست گذرکلید، هرگونه تماس تکمیل خودکار فرم (دریافت شرطی) درحال انجام را لغو کنید.
جریان میانجیگری مشروط (تکمیل خودکار فرم)
پیشنهادهای تکمیل خودکار فرم را هنگام بار شدن صفحه فعال کنید تا وقتی کاربران روی فیلدهای ورود به سیستم تمرکز میکنند، اصالتسنجی با گذرکلید بهصورت بومی ارائه شود:
- تشخیص ویژگی:
PublicKeyCredential.getClientCapabilities()را هنگام بار شدن صفحه فراخوانی کنید و اگرconditionalGetدردسترس نیست، از ورود به سیستم با گذرکلید صرفنظر کنید. - گزینههای رمزگشایی: رمزگشایی شیء JSON اطلاعات کاربری واکشیشده با
PublicKeyCredential.parseRequestOptionsFromJSON(). - فراخوانی Conditional Get:
navigator.credentials.get()را باmediation: "conditional"فراخوانی کنید و سیگنالAbortControllerرا ارسال کنید. این کار تکمیل خودکار را بدون نمایش کادر گفتگوی گذرکلید ثبت میکند. - Try/Catch Exception Segregation: Wrap
navigator.credentials.getcall in try/catch block:NotAllowedError: کاربر پیامواره ورود به سیستم با گذرکلید را لغو کرد یا زمان آن بهپایان رسید.AbortError: درخواست اصالتسنجی بهصورت برنامهنویسیشده لغو شد.
- Call Signal API: Wrap server verification
fetch()call in a try/catch block:- پیام خطایی به کاربر نشان دهید تا متوجه شود مشکل چیست.
signalUnknownCredential()را فقط زمانی فراخوانی کنید که سرور صریحاً با وضعیت HTTP404(اعتبارنامه پیدا نشد) پاسخ دهد و کاربر احراز هویت نشده باشد.- پارامتر
credentialIdکه بهsignalUnknownCredential()ارسال شده است باید دقیقاً رشته شناسه اطلاعات کاربری کدبندیشده با Base64URL باشد (مثلاًencoded.id)، نه شیء ArrayBuffer خامcredential.rawId.
- رمزگذاری پاسخ: اعتبارنامه
AuthenticatorAssertionResponseرا با.toJSON()رمزگذاری کنید و سپس آن را برای درستیسنجی به سرور ارسال کنید.
// optionsFetch and loginVerifyFetch are app-defined HTTP methods
import { optionsFetch, loginVerifyFetch } from "./api.js";
let autofillAbortController = new AbortController();
async function initializeConditionalAutofill() {
// Feature detect Conditional Get autofill support
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalGet === true) {
const loginOptionsJSON = await optionsFetch();
const publicKey =
PublicKeyCredential.parseRequestOptionsFromJSON(loginOptionsJSON);
try {
// Initiate Conditional UI form autofill suggestions
const credential = await navigator.credentials.get({
publicKey,
signal: autofillAbortController.signal,
mediation: "conditional",
});
// Segregated verification fetch
const encoded = credential.toJSON();
const response = await loginVerifyFetch(encoded);
if (!response.ok && response.status === 404) {
// Note: this code path runs pre-authentication, satisfying the unauth precondition
if (PublicKeyCredential.signalUnknownCredential) {
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encoded.id,
});
}
}
} catch (err) {
// Silently swallow expected client WebAuthn exceptions
if (["NotAllowedError", "AbortError"].includes(err.name)) {
return;
}
console.error("Unexpected conditional get error:", err);
}
}
}
async function triggerButtonAuthentication() {
// Abort any pending Conditional Get call to prevent passkey prompt collisions
autofillAbortController.abort();
autofillAbortController = new AbortController(); // Reset controller for next triggers
const loginOptionsJSON = await optionsFetch();
const publicKey =
PublicKeyCredential.parseRequestOptionsFromJSON(loginOptionsJSON);
let credential;
try {
// Passkey explicit prompt trigger
credential = await navigator.credentials.get({
publicKey,
signal: autofillAbortController.signal,
});
} catch (err) {
if (err.name === "NotAllowedError") {
console.log("User cancelled passkey login.");
} else if (err.name === "AbortError") {
console.log("The authentication operation was aborted.");
}
// Re-arm Conditional autofill Suggestions after cancelled explicit button prompts
initializeConditionalAutofill();
return; // Safe exit
}
// Segregated verification try/catch (HTTP 404 trigger)
const encoded = credential.toJSON();
try {
const response = await loginVerifyFetch(encoded);
if (!response.ok && response.status === 404) {
// Note: this code path runs pre-authentication, satisfying the unauth precondition
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encoded.id, // Base64URL-encoded credential ID
});
}
} catch (serverErr) {
console.error("Verification request error:", serverErr);
}
}
// Trigger Conditional Get on load
window.addEventListener("DOMContentLoaded", initializeConditionalAutofill);
راهبردهای جایگزین
جایگزین تشخیص ویژگی گذرکلید
همیشه «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.parseRequestOptionsFromJSON و PublicKeyCredential.prototype.toJSON نیز پشتیبانی میشوند.
import 'webauthn-polyfills';