本指南將詳細說明如何在使用者成功以密碼登入後,立即自動為使用者註冊密碼金鑰,盡可能減少摩擦,並提高密碼金鑰採用率。
適當的觸發時機
自動建立密碼金鑰 (也稱為條件式建立或登入後自動宣傳) 必須在使用者成功完成涉及密碼的完整登入程序後立即觸發。
- 請勿嘗試為無密碼流程 (例如魔術連結、簡訊動態密碼或身分聯盟) 建立條件式建立。
- 如果需要多重驗證,您必須等到所有驗證都成功,才能開始建立條件。
- 向建立端點發出要求前,請確認有效且經過驗證的使用者工作階段處於啟用狀態。
導入步驟
1. 取消先前的自動填入動作
如果登入頁面使用表單自動填入功能 (條件式 UI/Get),則必須取消有效的憑證 get 呼叫,以免瀏覽器發生衝突。
- 在呼叫
navigator.credentials.create()之前,請先對附加至待處理navigator.credentials.get()自動填入要求的AbortController呼叫abortController.abort()。
2. 功能偵測
使用 PublicKeyCredential.getClientCapabilities() 檢查 conditionalCreate,判斷是否可使用條件式建立功能。
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
// Conditional create is available
}
3. 使用條件式建立功能建立密碼金鑰
- 在
navigator.credentials.create()選項中傳遞mediation: 'conditional'。這會指示瀏覽器在背景或情境中,以不干擾的方式處理密碼金鑰建立流程,不會顯示突兀的強制回應對話方塊。 - 在
excludeCredentials中填入使用者現有的密碼金鑰憑證 ID,避免註冊重複的金鑰。
4. 背景錯誤處理
- 將密碼金鑰建立提示 (
navigator.credentials.create) 包裝在 try/catch 區塊中。您必須擷取並忽略一般面向使用者的例外狀況 (InvalidStateError、NotAllowedError、AbortError),不向使用者顯示任何錯誤 UI。
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)限制。如果瀏覽器不支援,系統會略過背景驗證同步作業,不會擲回瀏覽器例外狀況。
簡易 JSON 序列化備用方案
請務必安裝「webauthn-polyfills」,並將其匯入結構定義。請注意,只要支援 PublicKeyCredential,系統也會支援 PublicKeyCredential.parseCreationOptionsFromJSON 和 PublicKeyCredential.prototype.toJSON。
import 'webauthn-polyfills';