این راهنما جزئیات مربوط به نحوه فعال کردن کاربران برای مشاهده، تغییر نام، و حذف گذرکلیدهای ثبتشدهشان را ارائه میدهد، درحالیکه اطلاعات اعتباری ذخیرهشده و جزئیات نمایه کاربر را بااستفاده از Signal API بین سرور و مدیران گذرواژه کاربر همگامسازی میکند.
عملیات سمت سرور
لایه پایگاه داده و نقاط پایانی باطن شما باید از کنشهای CRUD رایج برای اطلاعات کاربری ثبتشده و همچنین بهروزرسانی جزئیات نمایه کاربر پشتیبانی کند. سرور که از کتابخانههای مختص چارچوب جدا شده است، نقطههای پایانی را برای موارد زیر نمایش میدهد:
- فهرست کردن همه اطلاعات اعتباری کاربر: همه سوابق
StoredPasskeyCredentialرا که با شناسه کاربر واردشده به سیستم مطابقت دارد واکشی کنید. - بهروزرسانی نامهای اطلاعات کاربری: پذیرفتن نام مستعار سفارشی جدید برای شناسه اطلاعات کاربری خاص و حفظ بهروزرسانی در سرور.
- حذف اطلاعات اعتباری: شناسه اطلاعات اعتباری خاصی را از پایگاه داده بردارید.
- بهروزرسانی جزئیات حساب کاربری: مقادیر بهروزشده
name(نام کاربری) وdisplayNameرا برای نمایه کاربر واردشده به سیستم بپذیرید تا کارخواه بتواند آنها را با ارائهدهنده گذرکلید همگامسازی کند.
// Node.js routing example for credential CRUD and user profile rename
router.get('/api/credentials', checkUserAuthenticated, async (req, res) => {
const list = await db.findCredentialsByUserId(req.user.id);
return res.json(list);
});
router.put('/api/credential/:id', checkUserAuthenticated, async (req, res) => {
const { id } = req.params;
const { name } = req.body;
const cred = await db.findCredentialById(id);
if (!cred || cred.passkeyUserId !== req.user.id) {
return res.status(404).json({ error: 'Credential not found.' });
}
cred.name = name;
await db.saveCredential(cred);
return res.json(cred);
});
router.delete('/api/credential/:id', checkUserAuthenticated, async (req, res) => {
const { id } = req.params;
const cred = await db.findCredentialById(id);
if (!cred || cred.passkeyUserId !== req.user.id) {
return res.status(404).json({ error: 'Credential not found.' });
}
await db.deleteCredential(id);
return res.json({ success: true });
});
router.put('/api/user', checkUserAuthenticated, async (req, res) => {
const { name, displayName } = req.body;
const updatedUser = await db.updateUser(req.user.id, { name, displayName });
return res.json(updatedUser);
});
میانای کاربر مدیریت سمت کارخواه
ارائه پانل تنظیمات اختصاصی که به کاربران امکان میدهد گزینههای اصالتسنجی ثبتشده و جزئیات نمایه حساب خود را بهراحتی بازرسی و مدیریت کنند:
- نمایش فهرست ذخیرهشده: فهرست را از نقطه پایانیتان واکشی کنید و ردیفهای اعتبارنامه را بهصورت جداگانه رندر کنید. اگر پاسخ خالی است، پیام وضعیت خالی مفیدی ارائه دهید (برای مثال، «گذرکلیدی پیدا نشد»).
- فراداده AAGUID را نگاشت کنید: برای هر گذرکلید، ویژگی
aaguidآن را در دفتر ثبت محلیتان جستجو کنید تا جزئیات ارائهدهنده آن ارائه شود. برای جزئیات بیشتر، بخش تعیین ارائهدهنده گذرکلید از AAGUID را ببینید. - الزامات واسط کاربر برای هر مورد: هر ردیف داخل محفظه فهرست باید موارد زیر را ارائه دهد:
- نماد ارائهدهنده: تصویر مشتقشده از AAGUID یا URI داده.
- نام ارائهدهنده/سفارشی: نام مشتقشده از AAGUID یا رشته تغییرنامیافته توسط کاربر.
- تاریخ ثبت: مُهر زمان تاریخ خام پایدار پایگاه داده
registeredAtکه برای نمایش به کارخواه به تاریخ قابلخواندن برای انسان قالببندی شده است. - تاریخ آخرین استفاده: مُهر زمان مبدأ خام پایدار در پایگاه داده
lastUsedAtکه برای نمایش به مشتری در قالب تاریخ قابلخواندن برای انسان (درصورت وجود) درآمده است. - دکمه تغییر نام: کنش تغییر نام را برای بهروزرسانی نام مستعار سفارشی اعتبارنامه در سرور (
PUT /api/credential/:id) راهاندازی میکند. توجه: تغییر نام مستعار گذرکلید بهصورت تکی یک تغییر برچسب سمت سرور است وsignalCurrentUserDetails()را فراخوانی نمیکند. - دکمه حذف: حذف اعتبارنامه (
DELETE /api/credential/:id) را راهاندازی میکند و شناسههای اعتبارنامه باقیمانده را ازطریقsignalAllAcceptedCredentials()همگامسازی میکند.
- میانای کاربر تغییر نام حساب کاربری:
- کنترلی ارائه دهید که به کاربر اجازه دهد نام کاربری حساب (
name) یاdisplayName(PUT /api/user) خود را بهروز کند و جزئیات بهروزشده کاربر را فوراً ازطریقPublicKeyCredential.signalCurrentUserDetails()با مدیر گذرواژه همگامسازی کند.
- کنترلی ارائه دهید که به کاربر اجازه دهد نام کاربری حساب (
- دکمه شرطی «ایجاد گذرکلید»:
- دکمه راهانداز ثبتنام «ایجاد گذرکلید» را بهطور برجسته در صفحه مدیریت ارائه دهید. قبلاز ارائه این عنصر میانای کاربر، صفحه باید قابلیتهای تشخیص ویژگی را بااستفاده از
PublicKeyCredential.getClientCapabilities()برای تأیید پشتیبانی از اصالتسنج پلاتفرم داشته باشد. اگر گذرکلیدها پشتیبانی نمیشوند، این دکمه را پنهان کنید و بهجای آن، کاربر را بهطور مناسب به ثبتنام در MFA استاندارد تشویق کنید. - اجازه ثبت کلید امنیتی با حذف
authenticatorSelection.authenticatorAttachmentدر تماسnavigator.credentials.create().
- دکمه راهانداز ثبتنام «ایجاد گذرکلید» را بهطور برجسته در صفحه مدیریت ارائه دهید. قبلاز ارائه این عنصر میانای کاربر، صفحه باید قابلیتهای تشخیص ویژگی را بااستفاده از
همگامسازی Signal API
Signal API به برنامه اجازه میدهد وضعیتهای اعتبارنامه را به مدیران گذرواژه منتقل کند و صندوقهای همگامسازیشده کاربر و پایگاه داده باطن شما را همگام نگه دارد.
- قانون تشخیص ویژگی و کدگذاری پارامتر:
- همیشه قبلاز فراخوانی روشهای Signal API، آنها را ازنظر ویژگی شناسایی کنید (
if (PublicKeyCredential.signalAllAcceptedCredentials)وif (PublicKeyCredential.signalCurrentUserDetails)). - همه پارامترهای شناسه
userIdو اطلاعات کاربری که به روشهای Signal API (signalAllAcceptedCredentials،signalCurrentUserDetails) ارسال میشوند باید رشتههای کدگذاریشده Base64URL باشند.
- همیشه قبلاز فراخوانی روشهای Signal API، آنها را ازنظر ویژگی شناسایی کنید (
- درحال شروع همگامسازی بار کردن صفحه:
- برنامه باید
signalAllAcceptedCredentials()را بهطور خودکار هنگام بار شدن صفحه مدیریت فراخوانی کند (برای مثال، داخل شنونده رویدادDOMContentLoaded، مقداردهی اولیه ماژول، یا قلاب نصب مؤلفه چارچوب مانندuseEffect).
- برنامه باید
- همگامسازی بهروزرسانیهای مدیریت:
- برنامه باید بلافاصله پساز واکشی،
signalAllAcceptedCredentials()را در کنترلکننده کلیک حذف اعتبارنامه فراخوانی کند. - برنامه باید بلافاصله پساز واکشی،
signalCurrentUserDetails()را در کنترلکننده کلیک تغییر نام حساب کاربری (nameیاdisplayName) فراخوانی کند.
- برنامه باید بلافاصله پساز واکشی،
// Client-side management synchronization ES module
import { listFetch, renameCredentialFetch, updateUserFetch, deleteFetch } from './api.js';
// Base64URL-encoded User ID string (illustration only)
const base64UrlUserId = "M2YPl-KGnA8";
async function syncAcceptedCredentials(currentCredentialsList) {
if (!window.PublicKeyCredential || !PublicKeyCredential.signalAllAcceptedCredentials) return;
try {
const credentialIds = currentCredentialsList.map(c => c.id); // Array of Base64URL credential ID strings
await PublicKeyCredential.signalAllAcceptedCredentials({
rpId, // RP ID must match the one defined on the server
userId: base64UrlUserId, // User ID Base64URL-encoded string
allAcceptedCredentialIds: credentialIds
});
} catch (e) {
console.error('SignalAllAcceptedCredentials sync failure:', e);
}
}
async function loadManagementPanel() {
const response = await listFetch();
const list = await response.json();
renderUI(list);
// Sync accepted credentials on initial load
await syncAcceptedCredentials(list);
}
async function performDelete(credentialId) {
const response = await deleteFetch(credentialId);
if (response.ok) {
const updatedResponse = await listFetch();
const updatedList = await updatedResponse.json();
renderUI(updatedList);
// Sync remaining accepted credentials after deletion
await syncAcceptedCredentials(updatedList);
}
}
// Renaming a passkey's nickname updates the server record only
async function performCredentialRename(credentialId, newCredentialName) {
const response = await renameCredentialFetch(credentialId, { name: newCredentialName });
if (response.ok) {
const updatedResponse = await listFetch();
renderUI(await updatedResponse.json());
}
}
// Renaming the user's account username or displayName triggers signalCurrentUserDetails
async function performUserRename(rpId, userId, updatedName, updatedDisplayName) {
const response = await updateUserFetch({ name: updatedName, displayName: updatedDisplayName });
if (response.ok && window.PublicKeyCredential && PublicKeyCredential.signalCurrentUserDetails) {
try {
await PublicKeyCredential.signalCurrentUserDetails({
rpId, // RP ID must match the one defined on the server
userId, // Base64URL-encoded user ID
name: updatedName, // Updated username
displayName: updatedDisplayName // Updated display name
});
} catch (e) {
console.error('SignalCurrentUserDetails sync failure:', e);
}
}
}
window.addEventListener('DOMContentLoaded', loadManagementPanel);
تعیین ارائهدهنده گذرکلید از AAGUID
AAGUID (شناسه منحصربهفرد جهانی گواهی اصالتسنج) شناسهای ۱۲۸ بیتی است که مدل اصالتسنج را نشان میدهد، نه یک نمونه خاص را. این شناسه درطول ثبت گذرکلید در دادههای اصالتسنج گنجانده میشود و میتوان از آن برای تعیین اینکه کدام ارائهدهنده گذرکلید (برای مثال، «مدیر گذرواژه Google»، iCloud Keychain، 1Password) اعتبارنامه را ایجاد کرده است استفاده کرد.
از AAGUID فقط باید برای کمک به کاربران در مدیریت گذرکلید استفاده شود. میتوان آن را تغییر داد، مگراینکه ازنظر رمزنگاری تأیید شده باشد، که درحالحاضر گذرکلیدهای پلاتفرم از آن پشتیبانی نمیکنند.
۱. AAGUID Registry
نگاشت JSON نگهداریشده توسط انجمن از AAGUID به نامها و نمادهای ارائهدهنده در اینجا دردسترس است:
https://raw.githubusercontent.com/passkeydeveloper/passkey-authenticator-aaguids/refs/heads/main/combined_aaguid.json
هر ورودی طرحواره زیر را دارد:
{
"<aaguid-uuid>": {
"name": "Provider Name",
"icon_light": "data:image/png;base64,...",
"icon_dark": "data:image/png;base64,..."
}
}
۲. استفاده از AAGUID پساز ثبتنام
پساز درستیسنجی پاسخ ثبتنام، aaguid را از نتیجه ثبتنام بخوانید و آن را با دفتر ثبت مقایسه کنید تا name و providerIcon اطلاعات کاربری را پر کنید:
قبلاز جستجوی AAGUID در دفتر ثبت، بررسی کنید که آیا با '00000000-0000-0000-0000-000000000000' برابر است یا نه. If so, skip the registry lookup and set name to a fallback (e.g. device name from user-agent, or "Unknown passkey provider") and providerIcon to undefined. فقط برای AAGUIDهای غیرصفر، رجیستری را جستجو کنید.
import aaguids from './aaguids.json' with { type: 'json' };
const { aaguid } = registrationInfo;
if (aaguid === '00000000-0000-0000-0000-000000000000') {
// use the device name as the passkey provider based on
// the information derived from the user agent string,
// or just say "Unknown passkey provider"
} else {
const provider = aaguids[aaguid];
const credential = {
// ...other fields
aaguid,
name: provider?.name || 'Unknown passkey provider',
providerIcon: provider?.icon_light,
};
}
راهبردهای جایگزین
جایگزین تشخیص ویژگی گذرکلید
همیشه «webauthn-polyfills» را نصب کنید و آن را در بافت وارد کنید.
درنظر بگیرید که تا زمانی که از PublicKeyCredential پشتیبانی میشود، از PublicKeyCredential.getClientCapabilities نیز پشتیبانی میشود.
import 'webauthn-polyfills';
جایگزین همگامسازی Signal API
اگر مرورگر از PublicKeyCredential.parseRequestOptionsFromJSON پشتیبانی نمیکند، از «webauthn-polyfills» استفاده کنید:
<script type="module">
if (!PublicKeyCredential.parseRequestOptionsFromJSON) {
await import('https://unpkg.com/webauthn-polyfills');
}
</script>
این کار همچنین پشتیبانی از PublicKeyCredential.prototype.toJSON را اضافه میکند.