Tạo trải nghiệm đăng nhập sử dụng khoá truy cập trong khi vẫn chứa những người dùng sử dụng mật khẩu hiện tại.
Khoá truy cập thay thế mật khẩu và giúp tài khoản người dùng trên web an toàn, đơn giản và dễ sử dụng hơn. Tuy nhiên, quá trình chuyển đổi từ phương thức xác thực dựa trên mật khẩu sang dựa trên khoá truy cập có thể khiến trải nghiệm người dùng trở nên phức tạp. Việc sử dụng tính năng tự động điền vào biểu mẫu để đề xuất khoá truy cập có thể giúp tạo ra một trải nghiệm hợp nhất.
Tại sao bạn nên dùng tính năng tự động điền biểu mẫu để đăng nhập bằng khoá truy cập?
Với khoá truy cập, người dùng chỉ cần sử dụng vân tay, khuôn mặt hoặc mã PIN của thiết bị để đăng nhập vào trang web.
Tốt nhất là không cần người dùng sử dụng mật khẩu và quy trình xác thực có thể đơn giản như một nút đăng nhập. Khi người dùng nhấn vào nút này, hộp thoại bộ chọn tài khoản sẽ bật lên, người dùng có thể chọn một tài khoản, mở khoá màn hình để xác minh và đăng nhập.
Tuy nhiên, việc chuyển đổi từ phương thức xác thực bằng mật khẩu sang phương thức xác thực dựa trên khoá truy cập có thể khó khăn. Khi người dùng chuyển sang sử dụng khoá truy cập, vẫn sẽ có những người sử dụng mật khẩu và trang web cần phải phù hợp với cả hai kiểu người dùng này. Bản thân người dùng không nên nhớ họ đã chuyển sang khoá truy cập trên những trang web nào. Vì vậy, việc yêu cầu người dùng chọn phương thức để sử dụng trước sẽ mang lại trải nghiệm kém.
Khoá truy cập cũng là một công nghệ mới. Việc giải thích về các lỗi này và đảm bảo người dùng cảm thấy thoải mái khi sử dụng chúng có thể là một thách thức đối với các trang web. Chúng ta có thể dựa vào trải nghiệm người dùng quen thuộc để tự động điền mật khẩu để giải quyết cả hai vấn đề.
Giao diện người dùng có điều kiện
Để xây dựng trải nghiệm người dùng hiệu quả cho cả người dùng khoá truy cập và mật khẩu, bạn có thể đưa khoá truy cập vào các đề xuất tự động điền. Đây được gọi là giao diện người dùng có điều kiện và thuộc tiêu chuẩn WebAuthn.
Ngay khi người dùng nhấn vào trường nhập tên người dùng, một hộp thoại đề xuất tự động điền sẽ bật lên để làm nổi bật các khoá truy cập đã lưu trữ cùng với các đề xuất tự động điền mật khẩu. Sau đó, người dùng có thể chọn một tài khoản và sử dụng phương thức khoá màn hình thiết bị để đăng nhập.
Bằng cách này, người dùng có thể đăng nhập vào trang web của bạn bằng biểu mẫu hiện có như thể không có gì thay đổi, nhưng với lợi ích bảo mật bổ sung của khoá truy cập (nếu có).
Cách thức hoạt động
Để xác thực bằng khoá truy cập, hãy sử dụng API WebAuthn.
4 thành phần trong quy trình xác thực khoá truy cập là: người dùng:
- Phần phụ trợ: Máy chủ phụ trợ lưu giữ cơ sở dữ liệu tài khoản lưu trữ khoá công khai và siêu dữ liệu khác về khoá truy cập.
- Giao diện người dùng: Giao diện người dùng giao tiếp với trình duyệt và gửi yêu cầu tìm nạp đến phần phụ trợ.
- Trình duyệt: Trình duyệt của người dùng đang chạy JavaScript của bạn.
- Authenticator: Trình xác thực của người dùng có chức năng tạo và lưu trữ khoá truy cập. Tệp này có thể trên cùng một thiết bị với trình duyệt (ví dụ: khi sử dụng Windows Hello) hoặc trên một thiết bị khác, chẳng hạn như điện thoại.
- Ngay khi người dùng truy cập vào giao diện người dùng, giao diện người dùng sẽ yêu cầu một thử thách từ phần phụ trợ để xác thực bằng khoá truy cập và sẽ gọi
navigator.credentials.get()
để bắt đầu xác thực bằng khoá truy cập. Thao tác này sẽ trả về mộtPromise
. - Khi người dùng đặt con trỏ vào trường đăng nhập, trình duyệt sẽ hiển thị hộp thoại tự động điền mật khẩu, bao gồm cả khoá truy cập. Một hộp thoại xác thực sẽ xuất hiện nếu người dùng chọn một khoá truy cập.
- Sau khi người dùng xác minh danh tính của họ bằng phương thức khoá màn hình của thiết bị, lời hứa sẽ được giải quyết và thông tin xác thực khoá công khai sẽ được trả về giao diện người dùng.
- Giao diện người dùng sẽ gửi thông tin xác thực khoá công khai đến phần phụ trợ. Phần phụ trợ xác minh chữ ký dựa vào khoá công khai của tài khoản trùng khớp trong cơ sở dữ liệu. Nếu thành công thì người dùng đã được đăng nhập.
Điều kiện tiên quyết
Giao diện người dùng WebAuthn có điều kiện được hỗ trợ công khai trong Safari trên iOS 16, iPadOS 16 và MacOS Ventura. Ứng dụng này cũng có trên Chrome trên Android, macOS và Windows 11 22H2.
Xác thực bằng khoá truy cập thông qua tính năng tự động điền biểu mẫu
Khi người dùng muốn đăng nhập, bạn có thể thực hiện một lệnh gọi get
WebAuthn có điều kiện để cho biết rằng các khoá truy cập có thể được đưa vào các đề xuất tự động điền. Lệnh gọi có điều kiện đến API navigator.credentials.get()
của WebAuthn không hiển thị giao diện người dùng và vẫn ở trạng thái chờ xử lý cho đến khi người dùng chọn một tài khoản để đăng nhập dựa trên các đề xuất tự động điền. Nếu người dùng chọn một khoá truy cập, trình duyệt sẽ giải quyết lời hứa đó bằng một thông tin xác thực thay vì điền vào biểu mẫu đăng nhập. Khi đó, trang có trách nhiệm đăng nhập người dùng.
Chú thích trường nhập biểu mẫu
Nếu cần, hãy thêm thuộc tính autocomplete
vào trường tên người dùng input
.
Thêm username
và webauthn
làm mã thông báo để cho phép ứng dụng đề xuất khoá truy cập.
<input type="text" name="username" autocomplete="username webauthn" ...>
Phát hiện tính năng
Trước khi gọi lệnh gọi API WebAuthn có điều kiện, hãy kiểm tra xem:
- Trình duyệt hỗ trợ WebAuthn.
- Trình duyệt hỗ trợ giao diện người dùng có điều kiện WebAuthn.
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.
if (window.PublicKeyCredential &&
PublicKeyCredential.isConditionalMediationAvailable) {
// Check if conditional mediation is available.
const isCMA = await PublicKeyCredential.isConditionalMediationAvailable();
if (isCMA) {
// Call WebAuthn authentication
}
}
Tìm nạp thử thách qua máy chủ bên bị hạn chế
Tìm nạp thử thách từ máy chủ bên bị hạn chế cần gọi navigator.credentials.get()
:
challenge
: Thử thách do máy chủ tạo trong ArrayBuffer. Đây là yêu cầu bắt buộc để ngăn chặn các cuộc tấn công phát lại. Hãy nhớ tạo thử thách mới cho mỗi lần đăng nhập và bỏ qua thử thách đó sau một khoảng thời gian nhất định hoặc sau một lần đăng nhập không thành công. Hãy coi mã này giống như mã thông báo CSRF.allowCredentials
: Một mảng thông tin xác thực được chấp nhận cho quy trình xác thực này. Truyền một mảng trống để cho phép người dùng chọn một khoá truy cập có sẵn trong danh sách do trình duyệt hiển thị.userVerification
: Cho biết liệu quy trình xác minh người dùng bằng phương thức khoá màn hình thiết bị là"required"
,"preferred"
hay"discouraged"
. Giá trị mặc định là"preferred"
, tức là trình xác thực có thể bỏ qua bước xác minh người dùng. Hãy đặt thuộc tính này thành"preferred"
hoặc bỏ qua thuộc tính này.
Gọi API WebAuthn bằng cờ conditional
để xác thực người dùng
Gọi navigator.credentials.get()
để bắt đầu chờ xác thực người dùng.
// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();
const publicKeyCredentialRequestOptions = {
// Server generated challenge
challenge: ****,
// The same RP ID as used during registration
rpId: 'example.com',
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
rpId
: Mã RP là một miền và trang web có thể chỉ định miền hoặc hậu tố có thể đăng ký. Giá trị này phải khớp với rp.id được dùng khi tạo khoá truy cập.
Hãy nhớ chỉ định mediation: 'conditional'
để yêu cầu có điều kiện.
Gửi thông tin xác thực khoá công khai được trả về đến máy chủ RP
Sau khi người dùng chọn một tài khoản và đồng ý bằng cách sử dụng phương thức khoá màn hình của thiết bị, lời hứa sẽ được giải quyết, trả về một đối tượng PublicKeyCredential
về giao diện người dùng RP.
Lời hứa có thể bị từ chối vì một số lý do. Bạn cần xử lý các lỗi cho phù hợp, tuỳ thuộc vào thuộc tính name
của đối tượng Error
:
NotAllowedError
: Người dùng đã huỷ thao tác.- Các trường hợp ngoại lệ khác: Đã xảy ra lỗi không mong muốn. Trình duyệt sẽ hiển thị hộp thoại lỗi cho người dùng.
Đối tượng thông tin xác thực khoá công khai chứa các thuộc tính sau:
id
: Mã được mã hoá base64url của thông tin xác thực khoá truy cập đã xác thực.rawId
: Phiên bản ArrayBuffer của mã thông tin xác thực.response.clientDataJSON
: Một ArrayBuffer của dữ liệu ứng dụng. Trường này chứa các thông tin như thách thức và nguồn gốc mà máy chủ RP sẽ cần xác minh.response.authenticatorData
: Mảng ArrayBuffer của dữ liệu trình xác thực. Trường này chứa các thông tin như mã nhận dạng RP.response.signature
: Một ArrayBuffer của chữ ký. Giá trị này là cốt lõi của thông tin xác thực và cần được xác minh trên máy chủ.response.userHandle
: Một ArrayBuffer chứa mã nhận dạng người dùng được đặt tại thời điểm tạo. Bạn có thể sử dụng giá trị này thay vì mã thông tin xác thực nếu máy chủ cần chọn các giá trị mã nhận dạng mà máy chủ sử dụng, hoặc nếu phần phụ trợ muốn tránh việc tạo chỉ mục trên mã thông tin xác thực.authenticatorAttachment
: Trả vềplatform
khi thông tin xác thực này đến từ thiết bị cục bộ. Nếu không,cross-platform
, đáng chú ý là khi người dùng sử dụng điện thoại để đăng nhập. Nếu người dùng cần sử dụng điện thoại để đăng nhập, hãy cân nhắc nhắc họ tạo khoá truy cập trên thiết bị cục bộ.type
: Trường này luôn được đặt thành"public-key"
.
Nếu sử dụng thư viện để xử lý đối tượng thông tin xác thực khoá công khai trên máy chủ RP, bạn nên gửi toàn bộ đối tượng đến máy chủ sau khi mã hoá một phần bằng base64url.
Xác minh chữ ký
Khi bạn nhận được thông tin xác thực khoá công khai trên máy chủ, hãy truyền thông tin đó đến thư viện FIDO để xử lý đối tượng.
Tra cứu mã thông tin xác thực trùng khớp với thuộc tính id
(Nếu bạn cần xác định tài khoản người dùng, hãy sử dụng thuộc tính userHandle
, chính là user.id
mà bạn đã chỉ định khi tạo thông tin xác thực). Xem có thể xác minh signature
của thông tin xác thực bằng khoá công khai đã lưu trữ hay không. Để làm như vậy, bạn nên sử dụng một thư viện phía máy chủ hoặc một giải pháp thay vì tự viết mã. Bạn có thể tìm thấy các thư viện nguồn mở trong kho lưu trữ GitHub Awesome-webauth.
Sau khi thông tin xác thực được xác minh bằng một khoá công khai trùng khớp, hãy đăng nhập người dùng.