Đăng nhập bằng khoá truy cập thông qua tính năng tự động điền biểu mẫu

Tạo một trải nghiệm đăng nhập tận dụng khoá truy cập trong khi vẫn hỗ trợ 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, việc chuyển đổi từ phương thức xác thực dựa trên mật khẩu sang phương thức xác thực 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 biểu mẫu để đề xuất khoá truy cập có thể giúp tạo ra trải nghiệm hợp nhất.

Tại sao bạn nên sử 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 có thể đăng nhập vào trang web chỉ bằng cách sử dụng vân tay, khuôn mặt hoặc mã PIN thiết bị.

Lý tưởng nhất là không có người dùng nhập 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, một 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ừ mật khẩu sang phương thức xác thực dựa trên khoá truy cập có thể gây khó khăn. Khi người dùng chuyển sang 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ớ trên những trang web mà họ đã chuyển sang khoá truy cập, 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ẽ có 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 các chỉ số và đảm bảo người dùng thấy thoải mái khi sử dụ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 những trải nghiệm quen thuộc của người dùng để tự động điền mật khẩu nhằm 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 nội dung đề 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, hộp thoại đề xuất tự động điền sẽ bật lên để làm nổi bật mã xác thực đã 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 của 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, bạn sử dụng API WebAuthn.

Bốn 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à các 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 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.
Sơ đồ xác thực khoá truy cập
  1. Ngay khi người dùng truy cập vào giao diện, giao diện người dùng sẽ yêu cầu một yêu cầu xác thực từ phần phụ trợ để xác thực bằng khoá truy cập và 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ột Promise.
  2. 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, trong đó có mã xác thực. Hộp thoại xác thực sẽ xuất hiện nếu người dùng chọn khoá truy cập.
  3. 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.
  4. Giao diện người dùng gửi thông tin xác thực khoá công khai đến phần phụ trợ. Phần phụ trợ sẽ 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. Tính nă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 lệnh gọi get WebAuthn có điều kiện để cho biết rằng khoá truy cập có thể được đưa vào nội dung đề xuất tự động điền. Lệnh gọi có điều kiện đến API WebAuthn navigator.credentials.get() không hiển thị giao diện người dùng và vẫn đang chờ xử lý cho đến khi người dùng chọn một tài khoản để đăng nhập từ các đề xuất tự động điền. Nếu người dùng chọn khoá truy cập, trình duyệt sẽ giải quyết lời hứa bằng thông tin xác thực thay vì điền vào biểu mẫu đăng nhập. Trang có trách nhiệm đăng nhập cho người dùng.

Chú thích trường nhập dữ liệu của biểu mẫu

Thêm thuộc tính autocomplete vào trường tên người dùng input nếu cần. Thêm usernamewebauthn làm mã thông báo để cho phép ứng dụng đề xuất mã xác thực.

<input type="text" name="username" autocomplete="username webauthn" ...>

Phát hiện tính năng

Trước khi gọi một 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 từ máy chủ bên bị hạn chế

Tìm nạp thử thách từ máy chủ RP được yêu cầu để gọi navigator.credentials.get():

  • challenge: Yêu cầu 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 khi một lần đăng nhập không xác thực được. Hãy coi mã này giống như một mã thông báo CSRF.
  • allowCredentials: Một loạt 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 hoạt động 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", nghĩa là trình xác thực có thể bỏ qua bước xác minh người dùng. Hãy đặt giá trị 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à một 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 dùng khi tạo khoá truy cập.

Hãy nhớ chỉ định mediation: 'conditional' để đặt 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 ý sử dụng phương thức khoá màn hình của thiết bị, lời hứa sẽ được phân giải để 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ý 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 ngoại lệ khác: Đã xảy ra sự cố không mong muốn. Trình duyệt 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ã nhận dạng đượ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ảng 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: Vùng đệm ArrayBuffer của dữ liệu trình xác thực. Trường này chứa các thông tin chẳng hạn như mã nhận dạng RP.
  • response.signature: Mảng 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 cho 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 việ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 đối tượng đó bằng base64url.

Xác minh chữ ký

Khi bạn nhận được thông tin xác thực về khoá công khai trên máy chủ, hãy truyền thông tin đó vào thư viện FIDO để xử lý đối tượng.

Tra cứu mã nhận dạng 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 userHandleuser.id mà bạn đã chỉ định khi tạo thông tin xác thực). Xem signature của thông tin xác thực có thể được xác minh bằng khoá công khai đã lưu trữ hay không. Để làm như vậy, bạn nên sử dụng thư viện phía máy chủ hoặc giải pháp thay vì viết mã của riêng mình. 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 cho người dùng.

Tài nguyên