Hướng dẫn này trình bày chi tiết cách tự động và âm thầm đăng ký khoá truy cập cho người dùng ngay sau khi họ đăng nhập thành công bằng mật khẩu, giúp giảm thiểu phiền hà và tăng tỷ lệ sử dụng khoá truy cập.
Thời điểm kích hoạt phù hợp
Tính năng tự động tạo khoá truy cập (còn gọi là Tạo có điều kiện hoặc quảng bá thầm lặng sau khi đăng nhập) CHỈ ĐƯỢC kích hoạt ngay sau khi đăng nhập thành công, đầy đủ bằng mật khẩu.
- Đừng cố tạo có điều kiện cho các quy trình không cần mật khẩu (ví dụ: đường liên kết dùng một lần, SMS OTP hoặc liên kết danh tính).
- Nếu cần xác thực đa yếu tố, bạn PHẢI đợi cho đến khi tất cả các yếu tố đều thành công trước khi bắt đầu tạo có điều kiện.
- Đảm bảo phiên người dùng hợp lệ và đã được xác thực đang hoạt động trước khi gửi yêu cầu đến các điểm cuối tạo.
Các bước triển khai
1. Huỷ các thao tác tự động điền trước đó
Nếu trang đăng nhập sử dụng tính năng tự động điền biểu mẫu (Giao diện người dùng có điều kiện/Get), thì lệnh gọi lấy thông tin xác thực đang hoạt động phải bị huỷ để tránh xung đột trình duyệt.
- Gọi
abortController.abort()trênAbortControllerđược đính kèm vào yêu cầu tự động điềnnavigator.credentials.get()đang chờ xử lý trước khi gọinavigator.credentials.create().
2. Phát hiện tính năng
Xác định xem có thể sử dụng tính năng Tạo có điều kiện hay không bằng cách kiểm tra conditionalCreate bằng PublicKeyCredential.getClientCapabilities().
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (capabilities.conditionalCreate) {
// Conditional create is available
}
3. Tạo khoá truy cập bằng tính năng Tạo có điều kiện
- Truyền
mediation: 'conditional'trong các tuỳ chọnnavigator.credentials.create(). Điều này báo hiệu cho trình duyệt xử lý quy trình tạo khoá truy cập một cách thầm lặng ở chế độ nền hoặc theo bối cảnh mà không hiển thị các hộp thoại phương thức gây phiền hà. - Điền mã thông tin xác thực khoá truy cập hiện có của người dùng vào
excludeCredentialsđể tránh đăng ký khoá trùng lặp.
4. Xử lý lỗi thầm lặng
- Gói lời nhắc tạo khoá truy cập (
navigator.credentials.create) trong một khối try/catch. Bạn PHẢI phát hiện và bỏ qua các ngoại lệ thông thường dành cho người dùng (InvalidStateError,NotAllowedError,AbortError) mà không hiển thị bất kỳ giao diện người dùng lỗi nào cho người dùng.
5. Xác minh sự hiện diện của người dùng phía máy chủ
- Điểm cuối xác minh phía máy chủ PHẢI nới lỏng yêu cầu về Sự hiện diện của người dùng (UP) (
requireUserPresence: false) CHỈ khi xác minh thông tin xác thực do trình kích hoạt tạo có điều kiện tạo ra. Bạn phải luôn bật chế độ xác minh nghiêm ngặt về sự hiện diện đối với các hoạt động tạo rõ ràng theo tiêu chuẩn.
6. Xử lý khéo léo khi không xác minh được máy chủ
- Nếu
navigator.credentials.create()thành công nhưng quá trình tìm nạp xác minh máy chủ trả về phản hồi không hợp lệ (ví dụ: xác minh chữ ký không thành công), hãy gọiPublicKeyCredential.signalUnknownCredential()để ngăn thông tin xác thực mồ côi tồn tại trong trình cung cấp khoá truy cập.
Ví dụ về mã
// 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
});
}
}
}
Chiến lược dự phòng
Dự phòng phát hiện tính năng khoá truy cập
Luôn cài đặt "webauthn-polyfills" và nhập vào ngữ cảnh.
Hãy cân nhắc rằng miễn là PublicKeyCredential được hỗ trợ, thì PublicKeyCredential.getClientCapabilities cũng được hỗ trợ.
import 'webauthn-polyfills';
Dự phòng đồng bộ hoá API tín hiệu
WebAuthn Signal API (webauthn-signals) là một tính năng tối ưu hoá tăng dần dùng để đồng bộ hoá trình quản lý mật khẩu với trạng thái thông tin xác thực của máy chủ.
- Trải nghiệm dự phòng: Được kiểm soát thông qua
if (PublicKeyCredential.signalUnknownCredential). Nếu không được hỗ trợ, quá trình đồng bộ hoá xác minh trong nền sẽ được bỏ qua một cách linh hoạt mà không gửi ngoại lệ của trình duyệt.
Dự phòng chuyển đổi tuần tự JSON dễ dàng
Luôn cài đặt "webauthn-polyfills" và nhập vào ngữ cảnh.
Hãy xem xét miễn là PublicKeyCredential được hỗ trợ, PublicKeyCredential.parseCreationOptionsFromJSON và PublicKeyCredential.prototype.toJSON cũng được hỗ trợ.
import 'webauthn-polyfills';