Mặc dù các thông tin đăng nhập FIDO (chẳng hạn như khoá truy cập) nhằm thay thế mật khẩu, nhưng hầu hết các thông tin này cũng có thể khiến người dùng không phải nhập tên người dùng. Thao tác này cho phép người dùng xác thực bằng cách chọn một tài khoản trong danh sách khoá truy cập mà họ có cho trang web hiện tại.
Các phiên bản trước của khoá bảo mật được thiết kế như phương thức xác thực 2 bước và yêu cầu mã nhận dạng của thông tin xác thực tiềm năng, do đó yêu cầu nhập tên người dùng. Thông tin xác thực mà khoá bảo mật có thể tìm thấy mà không biết mã nhận dạng của khoá được gọi là thông tin xác thực có thể tìm thấy. Hầu hết thông tin đăng nhập FIDO được tạo hiện nay đều là thông tin đăng nhập có thể tìm được; đặc biệt là khoá truy cập được lưu trữ trong một trình quản lý mật khẩu hoặc trên một khoá bảo mật hiện đại.
Để đảm bảo thông tin xác thực của bạn được tạo dưới dạng khoá truy cập (thông tin xác thực có thể phát hiện), hãy chỉ định residentKey
và requireResidentKey
khi tạo thông tin xác thực.
Các bên phụ thuộc (RP) có thể sử dụng thông tin xác thực có thể phát hiện được bằng cách bỏ qua allowCredentials
trong quá trình xác thực khoá truy cập. Trong những trường hợp này, trình duyệt hoặc hệ thống sẽ hiển thị cho người dùng danh sách khoá truy cập hiện có, được xác định bằng thuộc tính user.name
được đặt tại thời điểm tạo. Nếu người dùng chọn một giá trị, thì giá trị user.id
sẽ được đưa vào chữ ký thu được. Sau đó, máy chủ có thể sử dụng mã nhận dạng thông tin xác thực đã trả về hoặc mã nhận dạng thông tin xác thực đã nhập để tra cứu tài khoản thay vì tên người dùng đã nhập.
Giao diện người dùng bộ chọn tài khoản, chẳng hạn như các giao diện đã thảo luận trước đó, không bao giờ hiển thị thông tin xác thực không thể phát hiện.
requireResidentKey
và residentKey
Để tạo khoá truy cập, hãy chỉ định authenticatorSelection.residentKey
và authenticatorSelection.requireResidentKey
trên navigator.credentials.create()
với các giá trị được chỉ định như sau.
async function register () {
// ...
const publicKeyCredentialCreationOptions = {
// ...
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
requireResidentKey: true,
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
residentKey
:
'required'
: Bạn phải tạo thông tin xác thực có thể tìm thấy. Nếu không tạo được,NotSupportedError
sẽ được trả về.'preferred'
: RP muốn tạo thông tin xác thực có thể tìm thấy, nhưng chấp nhận thông tin xác thực không thể phát hiện.'discouraged'
: RP ưu tiên tạo thông tin xác thực không thể phát hiện, nhưng chấp nhận thông tin xác thực có thể phát hiện.
requireResidentKey
:
- Thuộc tính này được giữ lại để tương thích ngược từ WebAuthn cấp 1, một phiên bản cũ của quy cách. Đặt giá trị này thành
true
nếuresidentKey
là'required'
, nếu không, hãy đặt giá trị này thànhfalse
.
allowCredentials
RP có thể sử dụng allowCredentials
trên navigator.credentials.get()
để kiểm soát trải nghiệm xác thực bằng khoá truy cập. Thường có 3 loại trải nghiệm xác thực bằng khoá truy cập:
Hiển thị bộ chọn tài khoản theo phương thức phương thức
Với thông tin xác thực có thể khám phá, RP có thể hiển thị bộ chọn tài khoản phương thức để người dùng chọn một tài khoản để đăng nhập, sau đó là quy trình xác minh người dùng. Phương thức này phù hợp với quy trình xác thực khoá truy cập được bắt đầu bằng cách nhấn vào một nút dành riêng cho quy trình xác thực khoá truy cập.
Để đạt được trải nghiệm người dùng này, hãy bỏ qua hoặc truyền một mảng trống đến tham số allowCredentials
trong navigator.credentials.get()
.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
Hiển thị tính năng tự động điền khoá truy cập
Bộ chọn tài khoản theo phương thức bật lên được mô tả ở trên hoạt động tốt nếu hầu hết người dùng sử dụng khoá truy cập và có khoá truy cập trên thiết bị cục bộ. Đối với người dùng không có khoá truy cập cục bộ, hộp thoại phương thức vẫn xuất hiện và sẽ đề nghị người dùng cung cấp khoá truy cập từ một thiết bị khác. Trong khi chuyển đổi người dùng sang khoá truy cập, bạn nên tránh hiển thị giao diện người dùng đó cho những người dùng chưa thiết lập khoá truy cập.
Thay vào đó, lựa chọn khoá truy cập có thể được đưa vào lời nhắc tự động điền cho các trường trong biểu mẫu đăng nhập truyền thống, cùng với tên người dùng và mật khẩu đã lưu. Bằng cách này, người dùng có khoá truy cập có thể "điền" biểu mẫu đăng nhập bằng cách chọn khoá truy cập của họ, người dùng có cặp tên người dùng/mật khẩu đã lưu có thể chọn những cặp đó và người dùng không có khoá truy cập hoặc cặp tên người dùng/mật khẩu vẫn có thể nhập tên người dùng và mật khẩu của họ.
Trải nghiệm người dùng này là lý tưởng khi RP đang trong quá trình di chuyển với việc sử dụng kết hợp mật khẩu và khoá truy cập.
Để đạt được trải nghiệm người dùng này, ngoài việc truyền một mảng trống đến thuộc tính allowCredentials
hoặc bỏ qua tham số, hãy chỉ định mediation: 'conditional'
trên navigator.credentials.get()
và chú thích trường nhập username
HTML bằng autocomplete="username webauthn"
hoặc trường nhập password
bằng autocomplete="password webauthn"
.
Lệnh gọi đến navigator.credentials.get()
sẽ không hiển thị giao diện người dùng nào, nhưng nếu người dùng đặt tiêu điểm vào trường nhập dữ liệu được chú thích, thì mọi khoá truy cập hiện có sẽ được đưa vào các tuỳ chọn tự động điền. Nếu người dùng chọn một phương thức, họ sẽ trải qua quy trình xác minh mở khoá thiết bị thông thường, sau đó lời hứa do .get()
trả về sẽ phân giải bằng một kết quả. Nếu người dùng không chọn khoá truy cập, lời hứa sẽ không bao giờ được phân giải.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const cred = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>
Bạn có thể tìm hiểu cách xây dựng trải nghiệm người dùng này trong phần Đăng nhập bằng khoá truy cập thông qua tính năng tự động điền biểu mẫu, cũng như lớp học lập trình Triển khai khoá truy cập bằng tính năng tự động điền biểu mẫu trong ứng dụng web.
Xác thực lại
Trong một số trường hợp, chẳng hạn như khi sử dụng khoá truy cập để xác thực lại, giá trị nhận dạng của người dùng đã được biết. Trong trường hợp này, chúng ta muốn sử dụng khoá truy cập mà không cần trình duyệt hoặc hệ điều hành hiển thị bất kỳ hình thức bộ chọn tài khoản nào. Bạn có thể thực hiện việc này bằng cách truyền danh sách mã thông tin xác thực trong tham số allowCredentials
.
Trong trường hợp đó, nếu có bất kỳ thông tin xác thực nào được đặt tên có sẵn cục bộ, người dùng sẽ được nhắc mở khoá thiết bị ngay lập tức. Nếu không, người dùng sẽ được nhắc đưa ra một thiết bị khác (điện thoại hoặc khoá bảo mật) có thông tin xác thực hợp lệ.
Để mang lại trải nghiệm này cho người dùng, hãy cung cấp danh sách mã thông tin xác thực cho người dùng đăng nhập. RP có thể truy vấn các thông tin này vì người dùng đã được xác định. Cung cấp mã thông tin xác thực dưới dạng đối tượng PublicKeyCredentialDescriptor
trong thuộc tính allowCredentials
trong navigator.credentials.get()
.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// Provide a list of PublicKeyCredentialDescriptors:
allowCredentials: [{
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, {
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, ...]
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
Đối tượng PublicKeyCredentialDescriptor
bao gồm:
id
: Mã nhận dạng của thông tin xác thực khoá công khai mà RP đã nhận được khi đăng ký khoá truy cập.type
: Trường này thường là'public-key'
.transports
: Gợi ý về các công cụ di chuyển mà thiết bị có thông tin đăng nhập này hỗ trợ, được các trình duyệt sử dụng để tối ưu hoá giao diện người dùng yêu cầu người dùng trình bày một thiết bị bên ngoài. Danh sách này (nếu được cung cấp) phải chứa kết quả của lệnh gọigetTransports()
trong quá trình đăng ký từng thông tin xác thực.
Tóm tắt
Thông tin xác thực có thể khám phá được giúp trải nghiệm đăng nhập bằng khoá truy cập trở nên thân thiện hơn với người dùng bằng cách cho phép họ bỏ qua bước nhập tên người dùng. Với sự kết hợp của residentKey
, requireResidentKey
và allowCredentials
, các RP có thể mang đến trải nghiệm đăng nhập:
- Hiển thị bộ chọn tài khoản phương thức.
- Hiển thị tính năng tự động điền khoá truy cập.
- Xác thực lại.
Sử dụng thông tin xác thực có thể khám phá một cách khôn ngoan. Bằng cách đó, bạn có thể thiết kế trải nghiệm đăng nhập bằng khoá truy cập tinh vi mà người dùng sẽ thấy liền mạch và có nhiều khả năng tương tác hơn.