Hướng dẫn này tiếp tục hướng dẫn cách triển khai việc sử dụng khoá truy cập để xác thực. Trước khi người dùng có thể đăng nhập bằng khoá truy cập, bạn cũng phải hoàn tất các hướng dẫn trong phần Tạo khoá truy cập.
Để xác thực bằng khoá truy cập, trước tiên, bạn phải truy xuất các lựa chọn cần thiết để truy xuất khoá công khai từ máy chủ ứng dụng, sau đó gọi Credential Manager API để truy xuất khoá công khai. Sau đó, hãy xử lý phản hồi đăng nhập một cách thích hợp.
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 để đăng nhập người dùng bằng 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 phía máy chủ của ứng dụng. Để 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 Xác thực bằng khoá truy cập phía máy chủ.
Để truy xuất mọi tuỳ chọn mật khẩu và khoá truy cập được liên kết với tài khoản của người dùng, hãy hoàn tất các bước sau:
- Nhận các lựa chọn yêu cầu thông tin đăng nhập từ máy chủ: Đưa ra yêu cầu từ ứng dụng đến máy chủ xác thực để bắt đầu quy trình đăng nhập bằng khoá truy cập. Từ máy chủ, hãy gửi các lựa chọn cần thiết để nhận thông tin đăng nhập khoá công khai, cũng như một thử thách duy nhất.
- Tạo đối tượng cần thiết để lấy thông tin đăng nhập khoá công khai: Gói các lựa chọn do máy chủ gửi trong một đối tượng
GetPublicKeyCredentialOption - (không bắt buộc) Chuẩn bị getCredential: Trong Android 14 trở lên, bạn có thể giảm độ trễ bằng cách hiện bộ chọn tài khoản thông qua phương thức
prepareGetCredential()trước khi gọigetCredential(). - Khởi chạy quy trình đăng nhập: Gọi phương thức
getCredential()để đăng nhập cho người dùng - Xử lý phản hồi: Xử lý từng phản hồi có thể có của thông tin đăng nhập.
- Xử lý các trường hợp ngoại lệ: Đảm bảo rằng bạn xử lý các trường hợp ngoại lệ một cách thích hợp.
1. Nhận các lựa chọn yêu cầu thông tin đăng nhập từ máy chủ
Yêu cầu máy chủ cung cấp các lựa chọn cần thiết để lấy thông tin đăng nhập khoá công khai, cũng như challenge (mỗi lần đăng nhập sẽ có một challenge riêng). Để tìm hiểu thêm về việc triển khai phía máy chủ, hãy xem phần Tạo thử thách và Tạo các lựa chọn yêu cầu thông tin đăng nhập.
Các lựa chọn sẽ có dạng như sau:
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
Để tìm hiểu thêm về các trường này, hãy xem bài đăng trên blog về cách đăng nhập bằng khoá truy cập.
2. Tạo đối tượng cần thiết để nhận thông tin đăng nhập khoá công khai
Trong ứng dụng, hãy dùng các lựa chọn để tạo một đối tượng GetPublicKeyCredentialOption.
Trong ví dụ sau, requestJson biểu thị các lựa chọn do máy chủ gửi.
// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()
// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
requestJson = requestJson
)
Sau đó, hãy bao bọc GetPublicKeyCredentialOption trong một đối tượng GetCredentialRequest.
val credentialRequest = GetCredentialRequest(
// Include all the sign-in options that your app supports.
listOf(getPasswordOption, getPublicKeyCredentialOption),
// Defines whether you prefer to use only immediately available
// credentials or hybrid credentials.
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)
3. Không bắt buộc: Giảm độ trễ đăng nhập
Trên Android 14 trở lên, bạn có thể giảm độ trễ khi hiện bộ chọn tài khoản thông qua phương thức prepareGetCredential() trước khi gọi getCredential().
Phương thức prepareGetCredential() trả về một đối tượng PrepareGetCredentialResponse đã được lưu vào bộ nhớ đệm. Nhờ đó, phương thức getCredential() ở bước tiếp theo sẽ mở bộ chọn tài khoản bằng dữ liệu được lưu vào bộ nhớ đệm.
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
4. Khởi động quy trình đăng nhập
Gọi phương thức getCredential() để cho người dùng thấy bộ chọn tài khoản. Hãy sử dụng đoạn mã sau đây làm tài liệu tham khảo về cách chạy quy trình đăng nhập:
coroutineScope {
try {
result = credentialManager.getCredential(
// Use an activity-based context to avoid undefined system UI
// launching behavior.
context = activityContext,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
5. Xử lý phản hồi
Xử lý phản hồi, có thể chứa một trong nhiều loại đối tượng thông tin đăng nhập.
fun handleSignIn(result: GetCredentialResponse) {
// Handle the successfully returned credential.
val credential = result.credential
when (credential) {
is PublicKeyCredential -> {
val responseJson = credential.authenticationResponseJson
// Share responseJson i.e. a GetCredentialResponse on your server to
// validate and authenticate
}
is PasswordCredential -> {
val username = credential.id
val password = credential.password
// Use id and password to send to your server to validate
// and authenticate
}
is CustomCredential -> {
// If you are also using any external sign-in libraries, parse them
// here with the utility functions provided.
if (credential.type == ExampleCustomCredential.TYPE) {
try {
val ExampleCustomCredential =
ExampleCustomCredential.createFrom(credential.data)
// Extract the required credentials and complete the authentication as per
// the federated sign in or any external sign in library flow
} catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
// Unlikely to happen. If it does, you likely need to update the dependency
// version of your external sign-in library.
Log.e(TAG, "Failed to parse an ExampleCustomCredential", e)
}
} else {
// Catch any unrecognized custom credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
}
PublicKeyCredential được trả về từ quá trình xác thực về cơ bản là một câu khẳng định đã ký, có cấu trúc như sau:
{
"id": "<credential ID>",
"type": "public-key",
"rawId": "<raw credential ID>",
"response": {
"clientDataJSON": "<signed client data containing challenge>",
"authenticatorData": "<authenticator metadata>",
"signature": "<digital signature to be verified>",
"userHandle": "<user ID from credential registration>"
}
}
Trên máy chủ, bạn phải xác minh thông tin đăng nhập. Để tìm hiểu thêm, hãy xem phần Xác minh và đăng nhập người dùng.
6. Xử lý các trường hợp ngoại lệ
Bạn nên xử lý tất cả các trường hợp ngoại lệ của lớp con GetCredentialException.
Để tìm hiểu cách xử lý từng trường hợp ngoại lệ, hãy xem hướng dẫn khắc phục sự cố.
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}