Trước khi người dùng có thể xác thực bằng khoá truy cập, trước tiên, ứng dụng của bạn phải đăng ký hoặc tạo khoá truy cập cho tài khoản của họ.
Để tạo khoá truy cập, hãy lấy thông tin chi tiết cần thiết để tạo khoá truy cập từ máy chủ ứng dụng của bạn, rồi gọi Credential Manager API. API này sẽ trả về một cặp khoá công khai và khoá riêng tư. Khoá riêng tư được trả về sẽ được lưu trữ trong một trình cung cấp thông tin xác thực (chẳng hạn như Trình quản lý mật khẩu của Google) dưới dạng khoá truy cập. Khoá công khai được lưu trữ trên máy chủ ứng dụng của bạn.
Điều kiện tiên quyết
Đảm bảo bạn đã thiết lập Digital Asset Links và nhắm đến các thiết bị chạy Android 9 (API cấp 28) trở lên.
Tổng quan
Hướng dẫn này tập trung vào những thay đổi cần thiết trong ứng dụng khách bên thứ ba để tạo khoá truy cập, đồng thời cung cấp thông tin tổng quan ngắn gọn về việc triển khai máy chủ ứng dụng bên thứ ba. Để tìm hiểu thêm về quy trình tích hợp phía máy chủ, hãy xem bài viết Đăng ký khoá truy cập phía máy chủ.
- Thêm các phần phụ thuộc vào ứng dụng: Thêm các thư viện Trình quản lý thông tin xác thực bắt buộc.
- Khởi tạo Trình quản lý thông tin xác thực: Tạo một thực thể Trình quản lý thông tin xác thực.
- Nhận các lựa chọn tạo thông tin đăng nhập từ máy chủ ứng dụng: Từ máy chủ ứng dụng, hãy gửi cho ứng dụng khách các thông tin chi tiết cần thiết để tạo khoá truy cập, chẳng hạn như thông tin về ứng dụng, người dùng, cũng như
challengevà các trường khác. - Yêu cầu khoá truy cập: Trong ứng dụng của bạn, hãy sử dụng thông tin chi tiết nhận được từ máy chủ ứng dụng để tạo một đối tượng
GetPublicKeyCredentialOptionvà sử dụng đối tượng này để gọi phương thứccredentialManager.getCredential()nhằm tạo khoá truy cập. - Xử lý phản hồi tạo khoá truy cập: Khi nhận được thông tin đăng nhập trên ứng dụng khách, bạn phải mã hoá, chuyển đổi tuần tự rồi gửi khoá công khai đến máy chủ ứng dụng. Bạn cũng phải xử lý từng trường hợp ngoại lệ có thể xảy ra trong trường hợp tạo khoá truy cập.
- Xác minh và lưu khoá công khai trên máy chủ: Hoàn tất các bước phía máy chủ để xác minh nguồn gốc của thông tin đăng nhập, sau đó lưu khoá công khai.
- Thông báo cho người dùng: Thông báo cho người dùng rằng khoá truy cập của họ đã được tạo.
1. Thêm phần phụ thuộc vào ứng dụng
Thêm các phần phụ thuộc sau vào tệp build.gradle của mô-đun ứng dụng:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.6.0-beta03") implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta03") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.6.0-beta03" implementation "androidx.credentials:credentials-play-services-auth:1.6.0-beta03" }
2. Khởi tạo Trình quản lý thông tin xác thực
Sử dụng ngữ cảnh ứng dụng hoặc hoạt động để tạo đối tượng CredentialManager.
// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)
3. Nhận các lựa chọn tạo thông tin đăng nhập từ máy chủ ứng dụng
Khi người dùng nhấp vào nút "Tạo khoá truy cập" hoặc khi người dùng mới đăng ký, hãy đưa ra yêu cầu từ ứng dụng của bạn đến máy chủ ứng dụng để lấy thông tin cần thiết nhằm bắt đầu quy trình đăng ký khoá truy cập.
Sử dụng một thư viện tuân thủ FIDO trong máy chủ ứng dụng để gửi cho ứng dụng khách của bạn thông tin cần thiết để tạo khoá truy cập, chẳng hạn như thông tin về người dùng, ứng dụng và các thuộc tính cấu hình bổ sung. Để tìm hiểu thêm, hãy xem phần Đăng ký khoá truy cập phía máy chủ.
Trong ứng dụng khách, hãy giải mã các lựa chọn tạo khoá công khai do máy chủ ứng dụng gửi. Các thông tin này thường được trình bày ở định dạng JSON. Để tìm hiểu thêm về cách giải mã này được thực hiện cho các ứng dụng web, hãy xem phần Mã hoá và giải mã. Đối với ứng dụng khách Android, bạn phải xử lý việc giải mã riêng.
Đoạn mã sau đây cho thấy cấu trúc của các lựa chọn tạo khoá công khai do máy chủ ứng dụng gửi:
{
"challenge": "<base64url-encoded challenge>",
"rp": {
"name": "<relying party name>",
"id": "<relying party host name>"
},
"user": {
"id": "<base64url-encoded user ID>",
"name": "<user name>",
"displayName": "<user display name>"
},
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
}
],
"attestation": "none",
"excludeCredentials": [
{
"id": "<base64url-encoded credential ID to exclude>",
"type": "public-key"
}
],
"authenticatorSelection": {
"requireResidentKey": true,
"residentKey": "required",
"userVerification": "required"
}
}
Các trường chính trong lựa chọn tạo khoá công khai bao gồm:
challenge: Một chuỗi ngẫu nhiên do máy chủ tạo ra, dùng để ngăn chặn các cuộc tấn công phát lại.rp: Thông tin chi tiết về ứng dụng.rp.name: Tên của ứng dụng.rp.id: Miền hoặc miền con của ứng dụng.
user: Thông tin chi tiết về người dùng.id: Mã nhận dạng duy nhất của người dùng. Giá trị này không được chứa thông tin nhận dạng cá nhân, chẳng hạn như địa chỉ email hoặc tên người dùng. Bạn có thể sử dụng một giá trị 16 byte ngẫu nhiên.name: Giá trị nhận dạng duy nhất cho tài khoản mà người dùng sẽ nhận ra, chẳng hạn như địa chỉ email hoặc tên người dùng. Thông tin này sẽ xuất hiện trong bộ chọn tài khoản. Nếu dùng tên người dùng, hãy sử dụng chính giá trị như khi xác thực mật khẩu.displayName: Tên thân thiện với người dùng (không bắt buộc) của tài khoản dùng để hiển thị trong bộ chọn tài khoản.
authenticatorSelection: Thông tin chi tiết về thiết bị sẽ được dùng để xác thực.authenticatorAttachment: Cho biết trình xác thực ưu tiên. Các giá trị có thể có như sau: –platform: Giá trị này được dùng cho một trình xác thực được tích hợp vào thiết bị của người dùng, chẳng hạn như cảm biến vân tay. –cross-platform: Giá trị này được dùng cho các thiết bị chuyển vùng, chẳng hạn như khoá bảo mật. Thông thường, bạn không dùng phương thức này trong bối cảnh khoá truy cập. – Không xác định (nên dùng): Việc không chỉ định giá trị này sẽ giúp người dùng linh hoạt tạo khoá truy cập trên thiết bị ưu tiên của họ. Trong hầu hết mọi trường hợp, tốt nhất là bạn không nên chỉ định tham số.requireResidentKey: Để tạo khoá truy cập, hãy đặt giá trị của trườngBooleannày thànhtrue.residentKey: Để tạo khoá truy cập, hãy đặt giá trị thànhrequired.userVerification: Dùng để chỉ định các yêu cầu xác minh người dùng trong quá trình đăng ký khoá truy cập. Các giá trị có thể có như sau: –preferred: Sử dụng giá trị này nếu bạn ưu tiên trải nghiệm người dùng hơn là biện pháp bảo vệ, chẳng hạn như trong những môi trường mà việc xác minh người dùng gây ra nhiều phiền toái hơn là biện pháp bảo vệ. –required: Sử dụng giá trị này nếu cần gọi một phương thức xác minh người dùng có trên thiết bị. –discouraged: Sử dụng giá trị này nếu bạn không nên dùng phương thức xác minh người dùng.
Để tìm hiểu thêm vềuserVerification, hãy xem phần tìm hiểu sâu về userVerification.
excludeCredentials: Liệt kê mã thông tin xác thực trong một mảng để ngăn việc tạo khoá truy cập trùng lặp nếu đã có một khoá truy cập của cùng một nhà cung cấp thông tin xác thực.
4. Yêu cầu khoá truy cập
Sau khi bạn phân tích cú pháp các lựa chọn tạo khoá công khai phía máy chủ, hãy tạo một khoá truy cập bằng cách bao bọc các lựa chọn này trong một đối tượng CreatePublicKeyCredentialRequest và gọi createCredential().
createPublicKeyCredentialRequest bao gồm những lợi ích sau:
requestJson: Các lựa chọn tạo thông tin đăng nhập do máy chủ ứng dụng gửi.preferImmediatelyAvailableCredentials: Đây là một trường Boolean không bắt buộc, xác định việc chỉ sử dụng thông tin xác thực có sẵn trên máy hoặc thông tin xác thực do nhà cung cấp thông tin xác thực đồng bộ hoá để thực hiện yêu cầu, thay vì thông tin xác thực của từ khoá bảo mật hay luồng khoá kết hợp. Sau đây là các cách sử dụng có thể:false(mặc định): Sử dụng giá trị này nếu lệnh gọi đến Trình quản lý thông tin xác thực được kích hoạt bằng một hành động rõ ràng của người dùng.true: Sử dụng giá trị này nếu Trình quản lý thông tin xác thực được gọi một cách tuỳ ý, chẳng hạn như khi mở ứng dụng lần đầu tiên.
Nếu bạn đặt giá trị thànhtruevà hiện không có thông tin xác thực nào, Trình quản lý thông tin xác thực sẽ không hiện giao diện người dùng và yêu cầu sẽ bị lỗi ngay lập tức, trả về NoCredentialException cho yêu cầu GET vàCreateCredentialNoCreateOptionExceptioncho yêu cầu CREATE.
origin: Trường này được tự động đặt cho các ứng dụng Android. Đối với các trình duyệt và ứng dụng có đặc quyền tương tự cần đặtorigin, hãy xem phần Đối với những ứng dụng có đặc quyền, hãy thay mặt cho bên khác thực hiện các lệnh gọi từ Trình quản lý thông tin xác thực.isConditional: Đây là một trường không bắt buộc và mặc định làfalse. Khi bạn đặt chế độ này thànhtruevà nếu người dùng không có khoá truy cập, thì bạn sẽ tự động tạo một khoá truy cập thay cho họ vào lần tiếp theo họ đăng nhập bằng mật khẩu đã lưu. Khoá truy cập được lưu trữ trong trình cung cấp thông tin đăng nhập của người dùng. Tính năng tạo có điều kiện yêu cầu phiên bản mới nhất củaandroidx.credentials.
Việc gọi hàm createCredential() sẽ khởi chạy giao diện người dùng trang tính dưới cùng tích hợp của Trình quản lý thông tin xác thực. Giao diện này nhắc người dùng sử dụng khoá truy cập và chọn một nhà cung cấp thông tin xác thực cũng như tài khoản để lưu trữ. Tuy nhiên, nếu isConditional được đặt thành true, thì giao diện người dùng trang tính dưới cùng sẽ không hiển thị và khoá truy cập sẽ được tự động tạo.
5. Xử lý phản hồi
Sau khi người dùng được xác minh bằng khoá màn hình của thiết bị, một khoá truy cập sẽ được tạo và lưu trữ trong trình cung cấp thông tin đăng nhập mà người dùng đã chọn.
Phản hồi sau khi bạn gọi createCredential() thành công là một đối tượng PublicKeyCredential.
PublicKeyCredential sẽ có dạng như sau:
{
"id": "<identifier>",
"type": "public-key",
"rawId": "<identifier>",
"response": {
"clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
"attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
},
"authenticatorAttachment": "platform"
}
Trong ứng dụng khách, hãy chuyển đổi đối tượng thành chuỗi rồi gửi đến máy chủ ứng dụng.
Thêm mã để xử lý các lỗi như minh hoạ trong đoạn mã sau:
fun handleFailure(e: CreateCredentialException) {
when (e) {
is CreatePublicKeyCredentialDomException -> {
// Handle the passkey DOM errors thrown according to the
// WebAuthn spec.
}
is CreateCredentialCancellationException -> {
// The user intentionally canceled the operation and chose not
// to register the credential.
}
is CreateCredentialInterruptedException -> {
// Retry-able error. Consider retrying the call.
}
is CreateCredentialProviderConfigurationException -> {
// Your app is missing the provider configuration dependency.
// Most likely, you're missing the
// "credentials-play-services-auth" module.
}
is CreateCredentialCustomException -> {
// You have encountered an error from a 3rd-party SDK. If you
// make the API call with a request object that's a subclass of
// CreateCustomCredentialRequest using a 3rd-party SDK, then you
// should check for any custom exception type constants within
// that SDK to match with e.type. Otherwise, drop or log the
// exception.
}
else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}")
}
}
6. Xác minh và lưu khoá công khai trên máy chủ ứng dụng
Trên máy chủ ứng dụng, bạn phải xác minh thông tin đăng nhập khoá công khai rồi lưu khoá công khai.
Để xác minh nguồn gốc của thông tin xác thực khoá công khai, hãy so sánh thông tin này với một danh sách cho phép gồm các ứng dụng đã được phê duyệt. Nếu một khoá có nguồn gốc không xác định, hãy từ chối khoá đó.
Cách lấy vân tay số SHA 256 của ứng dụng:
In chứng chỉ ký của ứng dụng phát hành bằng cách chạy lệnh sau trong một thiết bị đầu cuối:
keytool -list -keystore <path-to-apk-signing-keystore>Trong phản hồi, hãy xác định vân tay số SHA 256 của chứng chỉ ký, được đề cập là
Certificate fingerprints block:SHA256.Mã hoá vân tay số SHA256 bằng phương thức mã hoá base64url. Ví dụ này bằng Python minh hoạ cách mã hoá dấu vân tay đúng cách:
import binascii import base64 fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))Thêm
android:apk-key-hash: vào đầu kết quả của bước trước để bạn nhận được nội dung tương tự như sau:android:apk-key-hash:<encoded SHA 256 fingerprint>Kết quả phải khớp với một nguồn gốc được phép trên máy chủ ứng dụng của bạn. Nếu bạn có nhiều chứng chỉ ký (chẳng hạn như chứng chỉ để gỡ lỗi và phát hành) hoặc nhiều ứng dụng, hãy lặp lại quy trình và chấp nhận mọi nguồn gốc đều hợp lệ trên máy chủ ứng dụng.
7. Thông báo cho người dùng
Sau khi tạo khoá truy cập thành công, hãy thông báo cho người dùng về khoá truy cập và cho họ biết rằng họ có thể quản lý khoá truy cập trong ứng dụng nhà cung cấp thông tin đăng nhập hoặc trong phần cài đặt ứng dụng. Thông báo cho người dùng bằng cách sử dụng hộp thoại, thông báo hoặc thanh thông báo nhanh tuỳ chỉnh. Vì việc một thực thể độc hại tạo khoá truy cập ngoài ý muốn đòi hỏi phải có cảnh báo bảo mật ngay lập tức, hãy cân nhắc việc bổ sung các phương thức trong ứng dụng này bằng thông tin liên lạc bên ngoài, chẳng hạn như email.
Nâng cao trải nghiệm người dùng
Để nâng cao trải nghiệm người dùng trong khi triển khai tính năng đăng ký bằng Trình quản lý thông tin xác thực, hãy cân nhắc việc thêm chức năng khôi phục thông tin đăng nhập và ngăn chặn hộp thoại tự động điền.
Thêm chức năng khôi phục thông tin đăng nhập trên thiết bị mới
Để cho phép người dùng đăng nhập liền mạch vào tài khoản của họ trên một thiết bị mới, hãy triển khai chức năng Khôi phục thông tin đăng nhập. Khi thêm thông tin đăng nhập khôi phục bằng BackupAgent, người dùng sẽ đăng nhập khi họ mở ứng dụng đã khôi phục trên một thiết bị mới, cho phép họ sử dụng ứng dụng của bạn ngay lập tức.
Chặn tính năng tự động điền trên các trường thông tin đăng nhập (không bắt buộc)
Đối với những màn hình ứng dụng mà người dùng dự kiến sẽ sử dụng giao diện người dùng trang tính dưới cùng của Trình quản lý thông tin đăng nhập để xác thực, hãy thêm thuộc tính isCredential vào các trường tên người dùng và mật khẩu. Điều này ngăn các hộp thoại tự động điền (FillDialog và SaveDialog) trùng lặp với giao diện người dùng bảng dưới cùng của Trình quản lý thông tin xác thực.
Thuộc tính isCredential được hỗ trợ trên Android 14 trở lên.
Ví dụ sau đây minh hoạ cách bạn có thể thêm thuộc tính isCredential vào các trường tên người dùng và mật khẩu có liên quan trong các khung hiển thị có liên quan cho ứng dụng của mình:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:isCredential="true" />
Các bước tiếp theo
- Đăng nhập bằng khoá truy cập
- Quản lý khoá truy cập
- Tìm hiểu các luồng trải nghiệm người dùng khi sử dụng khoá truy cập