API Trình quản lý thông tin xác thực cho người dùng cho phép ứng dụng người dùng Android (còn gọi là "ví") quản lý và trình bày thông tin xác thực kỹ thuật số cho người xác minh.
Các khái niệm chính
Bạn cần làm quen với các khái niệm sau đây trước khi sử dụng Holder API.
Định dạng thông tin đăng nhập
Thông tin đăng nhập có thể được lưu trữ trong các ứng dụng ví ở nhiều định dạng thông tin đăng nhập. Đây là các định dạng quy định cách trình bày một thông tin xác thực và mỗi định dạng chứa thông tin sau về thông tin xác thực:
- Loại: Danh mục như bằng đại học hoặc giấy phép lái xe trên thiết bị di động.
- Thuộc tính: Các thuộc tính như họ và tên.
- Mã hoá: Cách thông tin đăng nhập được cấu trúc, ví dụ: SD-JWT hoặc mdoc
- Tính hợp lệ: Phương thức xác minh tính xác thực của thông tin đăng nhập bằng mật mã.
Mỗi định dạng thông tin đăng nhập sẽ mã hoá và xác thực theo cách hơi khác nhau, nhưng về chức năng thì chúng giống nhau.
Sổ đăng ký hỗ trợ 2 định dạng:
- SD-JWT: tuân thủ quy cách Chứng chỉ có thể xác minh dựa trên SD-JWT của IETF (SD-JWT VC).
- Tài liệu di động hoặc mdocs: tuân thủ quy cách ISO/IEC 18013-5:2021.
Trình xác minh có thể đưa ra yêu cầu OpenID4VP đối với SD-JWT và mdoc khi sử dụng Trình quản lý thông tin đăng nhập. Lựa chọn này sẽ khác nhau tuỳ thuộc vào trường hợp sử dụng và lựa chọn ngành.
Đăng ký siêu dữ liệu thông tin đăng nhập
Trình quản lý thông tin xác thực không lưu trữ trực tiếp thông tin xác thực của người dùng mà lưu trữ siêu dữ liệu của thông tin xác thực. Trước tiên, ứng dụng lưu trữ phải đăng ký siêu dữ liệu thông tin xác thực với Credential Manager bằng cách sử dụng RegistryManager. Quy trình đăng ký này tạo ra một bản ghi trong sổ đăng ký, có 2 mục đích chính:
- So khớp: Siêu dữ liệu thông tin đăng nhập đã đăng ký được dùng để so khớp với các yêu cầu của trình xác minh trong tương lai.
- Hiển thị: Các phần tử tuỳ chỉnh trên giao diện người dùng sẽ xuất hiện với người dùng trên giao diện bộ chọn thông tin đăng nhập.
Bạn sẽ sử dụng lớp OpenId4VpRegistry để đăng ký thông tin xác thực kỹ thuật số, vì lớp này hỗ trợ cả định dạng thông tin xác thực mdoc và SD-JWT. Bên xác minh sẽ gửi yêu cầu OpenID4VP để yêu cầu những thông tin xác thực này.
Đăng ký thông tin đăng nhập của ứng dụng
Để sử dụng Credential Manager Holder API, hãy thêm các phần phụ thuộc sau vào tập lệnh bản dựng của mô-đun ứng dụng:
Groovy
dependencies { // Use to implement credentials registrys implementation "androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04" implementation "androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04" implementation "androidx.credentials.registry:registry-provider:1.0.0-alpha04" implementation "androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04" }
Kotlin
dependencies { // Use to implement credentials registrys implementation("androidx.credentials.registry:registry-digitalcredentials-mdoc:1.0.0-alpha04") implementation("androidx.credentials.registry:registry-digitalcredentials-preview:1.0.0-alpha04") implementation("androidx.credentials.registry:registry-provider:1.0.0-alpha04") implementation("androidx.credentials.registry:registry-provider-play-services:1.0.0-alpha04") }
Tạo RegistryManager
Tạo một thực thể RegistryManager và đăng ký một yêu cầu OpenId4VpRegistry với thực thể đó.
// Create the registry manager
val registryManager = RegistryManager.create(context)
// The guide covers how to build this out later
val registryRequest = OpenId4VpRegistry(credentialEntries, id)
try {
registryManager.registerCredentials(registryRequest)
} catch (e: Exception) {
// Handle exceptions
}
Tạo yêu cầu OpenId4VpRegistry
Như đã đề cập trước đó, bạn sẽ cần đăng ký một OpenId4VpRegistry để xử lý yêu cầu OpenID4VP từ một trình xác minh. Chúng tôi giả định rằng bạn đã tải một số loại dữ liệu cục bộ bằng thông tin đăng nhập vào ví của mình (ví dụ: sdJwtsFromStorage). Giờ đây, bạn sẽ chuyển đổi các loại dữ liệu đó thành các loại dữ liệu tương đương DigitalCredentialEntry của Jetpack dựa trên định dạng của chúng – SdJwtEntry hoặc MdocEntry cho SD-JWT hoặc mdoc, tương ứng.
Thêm Sd-JWT vào sổ đăng ký
Liên kết từng thông tin xác thực SD-JWT cục bộ với một SdJwtEntry cho sổ đăng ký:
fun mapToSdJwtEntries(sdJwtsFromStorage: List<StoredSdJwtEntry>): List<SdJwtEntry> {
val list = mutableListOf<SdJwtEntry>()
for (sdJwt in sdJwtsFromStorage) {
list.add(
SdJwtEntry(
verifiableCredentialType = sdJwt.getVCT(),
claims = sdJwt.getClaimsList(),
entryDisplayPropertySet = sdJwt.toDisplayProperties(),
id = sdJwt.getId() // Make sure this cannot be readily guessed
)
)
}
return list
}
Thêm mdocs vào Registry
Ánh xạ thông tin xác thực mdoc cục bộ vào loại Jetpack MdocEntry:
fun mapToMdocEntries(mdocsFromStorage: List<StoredMdocEntry>): List<MdocEntry> {
val list = mutableListOf<MdocEntry>()
for (mdoc in mdocsFromStorage) {
list.add(
MdocEntry(
docType = mdoc.retrieveDocType(),
fields = mdoc.getFields(),
entryDisplayPropertySet = mdoc.toDisplayProperties(),
id = mdoc.getId() // Make sure this cannot be readily guessed
)
)
}
return list
}
Các điểm chính về mã
- Một phương thức định cấu hình trường
idlà đăng ký một mã nhận dạng thông tin đăng nhập đã mã hoá, để chỉ bạn mới có thể giải mã giá trị. - Bạn nên bản địa hoá các trường hiển thị trên giao diện người dùng cho cả hai định dạng.
Đăng ký thông tin đăng nhập
Kết hợp các mục đã chuyển đổi và đăng ký yêu cầu với RegistryManager:
val credentialEntries = mapToSdJwtEntries(sdJwtsFromStorage) + mapToMdocEntries(mdocsFromStorage)
val openidRegistryRequest = OpenId4VpRegistry(
credentialEntries = credentialEntries,
id = "my-wallet-openid-registry-v1" // A stable, unique ID to identify your registry record.
)
Bây giờ, chúng ta đã sẵn sàng đăng ký thông tin đăng nhập của bạn bằng CredentialManager.
try {
val response = registryManager.registerCredentials(openidRegistryRequest)
} catch (e: Exception) {
// Handle failure
}
Bạn hiện đã đăng ký thông tin đăng nhập của mình bằng Trình quản lý thông tin xác thực.
Quản lý siêu dữ liệu ứng dụng
Siêu dữ liệu mà ứng dụng lưu trữ của bạn đăng ký với CredentialManager có các thuộc tính sau:
- Tính ổn định: Thông tin được lưu cục bộ và vẫn tồn tại sau khi khởi động lại.
- Bộ nhớ biệt lập: Bản ghi đăng ký của mỗi ứng dụng được lưu trữ riêng biệt, nghĩa là một ứng dụng không thể thay đổi bản ghi đăng ký của một ứng dụng khác.
- Bản cập nhật có khoá: Mỗi bản ghi trong sổ đăng ký của ứng dụng đều được khoá bằng một
id, cho phép xác định lại, cập nhật hoặc xoá bản ghi. - Cập nhật siêu dữ liệu: Bạn nên cập nhật siêu dữ liệu được duy trì bất cứ khi nào ứng dụng của bạn thay đổi hoặc được tải lần đầu. Nếu một sổ đăng ký được gọi nhiều lần trong cùng một
id, thì lệnh gọi gần đây nhất sẽ ghi đè tất cả các bản ghi trước đó. Để cập nhật, hãy đăng ký lại mà không cần xoá bản ghi cũ trước.
Không bắt buộc: Tạo một đối tượng so khớp
Trình so khớp là một tệp nhị phân Wasm mà Trình quản lý thông tin xác thực chạy trong một hộp cát để lọc thông tin xác thực đã đăng ký theo yêu cầu của Trình xác minh đến.
- Trình so khớp mặc định: Lớp
OpenId4VpRegistrytự động bao gồm trình so khớpOpenId4VPmặc định (OpenId4VpDefaults.DEFAULT_MATCHER) khi bạn tạo thực thể cho lớp này. Đối với tất cả các trường hợp sử dụng OpenID4VP tiêu chuẩn, thư viện sẽ xử lý việc so khớp cho bạn. - Trình so khớp tuỳ chỉnh: Bạn chỉ triển khai trình so khớp tuỳ chỉnh nếu đang hỗ trợ một giao thức không chuẩn và giao thức này yêu cầu logic so khớp riêng.
Xử lý thông tin đăng nhập đã chọn
Khi người dùng chọn một thông tin xác thực, ứng dụng người nắm giữ cần xử lý yêu cầu.
Bạn cần xác định một Hoạt động lắng nghe bộ lọc ý định androidx.credentials.registry.provider.action.GET_CREDENTIAL.
Ví mẫu của chúng tôi minh hoạ quy trình này.
Ý định này sẽ khởi chạy hoạt động của bạn bằng yêu cầu của Trình xác minh và nguồn gốc gọi, mà bạn trích xuất bằng hàm PendingIntentHandler.retrieveProviderGetCredentialRequest. Phương thức này trả về một ProviderGetCredentialRequest chứa tất cả thông tin liên quan đến yêu cầu của trình xác minh. Có 3 thành phần chính:
- Ứng dụng gọi: Ứng dụng đã đưa ra yêu cầu, có thể truy xuất bằng
getCallingAppInfo. - Thông tin đăng nhập đã chọn: Thông tin về ứng viên mà người dùng đã chọn, được truy xuất thông qua
selectedCredentialSet extension method; thông tin này sẽ khớp với mã thông tin đăng nhập mà bạn đã đăng ký. - Yêu cầu cụ thể: Yêu cầu cụ thể do trình xác minh đưa ra, được truy xuất từ phương thức
getCredentialOptions. Đối với quy trình yêu cầu Thông tin đăng nhập kỹ thuật số, bạn có thể thấy mộtGetDigitalCredentialOptionduy nhất trong danh sách này.
Thông thường, trình xác minh sẽ đưa ra yêu cầu trình bày thông tin đăng nhập kỹ thuật số mà bạn có thể xử lý bằng đoạn mã mẫu sau:
request.credentialOptions.forEach { option ->
if (option is GetDigitalCredentialOption) {
Log.i(TAG, "Got DC request: ${option.requestJson}")
processRequest(option.requestJson)
}
}
Bạn có thể xem ví dụ về vấn đề này trong ví mẫu.
Kiểm tra danh tính của người xác minh
- Trích xuất
ProviderGetCredentialRequesttừ ý định:
val request = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)
- Kiểm tra nguồn gốc có đặc quyền: Các ứng dụng có đặc quyền (chẳng hạn như trình duyệt web) có thể thay mặt cho các trình xác minh khác thực hiện lệnh gọi bằng cách đặt tham số nguồn gốc. Để truy xuất nguồn gốc này, bạn phải truyền danh sách phương thức gọi có đặc quyền và đáng tin cậy (danh sách cho phép ở định dạng JSON) đến API
getOrigin()củaCallingAppInfo.
val origin = request?.callingAppInfo?.getOrigin(
privilegedAppsJson // Your allow list JSON
)
Nếu nguồn không trống: Nguồn được trả về nếu packageName và dấu vân tay chứng chỉ thu được từ signingInfo khớp với dấu vân tay của một ứng dụng tìm thấy trong danh sách cho phép được truyền đến API getOrigin(). Sau khi nhận được giá trị nguồn, ứng dụng của nhà cung cấp sẽ coi đây là lệnh gọi đặc quyền và đặt nguồn này trên phản hồi OpenID4VP, thay vì tính toán nguồn bằng chữ ký của ứng dụng gọi.
Trình quản lý mật khẩu của Google sử dụng một danh sách cho phép có sẵn công khai cho các lệnh gọi đến getOrigin(). Là nhà cung cấp thông tin xác thực, có thể bạn phải sử dụng danh sách này hoặc cung cấp danh sách riêng ở định dạng JSON mà API mô tả. Nhà cung cấp có quyền chọn danh sách nào được sử dụng. Để có quyền truy cập đặc quyền với nhà cung cấp thông tin xác thực bên thứ ba, hãy tham khảo tài liệu do bên thứ ba cung cấp.
Nếu nguồn gốc trống, thì yêu cầu của trình xác minh là từ một ứng dụng Android. Nguồn gốc của ứng dụng cần được đưa vào phản hồi OpenID4VP phải được tính là android:apk-key-hash:<encoded SHA 256 fingerprint>.
val appSigningInfo = request?.callingAppInfo?.signingInfoCompat?.signingCertificateHistory[0]?.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val certHash = Base64.encodeToString(md.digest(appSigningInfo), Base64.NO_WRAP or Base64.NO_PADDING)
return "android:apk-key-hash:$certHash"
Kết xuất giao diện người dùng của phần giữ chỗ
Khi một thông tin đăng nhập được chọn, ứng dụng lưu trữ sẽ được gọi, hướng dẫn người dùng thông qua giao diện người dùng của ứng dụng. Có hai cách tiêu chuẩn để xử lý quy trình này:
- Nếu cần xác thực thêm người dùng để phát hành thông tin đăng nhập, hãy sử dụng BiometricPrompt API. Điều này được minh hoạ trong mẫu.
- Nếu không, nhiều ví chọn cách trả về âm thầm bằng cách hiển thị một hoạt động trống ngay lập tức chuyển dữ liệu trở lại ứng dụng gọi. Điều này giúp giảm thiểu số lượt nhấp của người dùng và mang lại trải nghiệm liền mạch hơn.
Trả về phản hồi thông tin xác thực
Sau khi ứng dụng lưu trữ sẵn sàng gửi kết quả trở lại, hãy hoàn tất hoạt động bằng phản hồi về thông tin xác thực:
PendingIntentHandler.setGetCredentialResponse(
resultData,
GetCredentialResponse(DigitalCredential(response.responseJson))
)
setResult(RESULT_OK, resultData)
finish()
Nếu có trường hợp ngoại lệ, bạn cũng có thể gửi thông tin ngoại lệ về thông tin đăng nhập:
PendingIntentHandler.setGetCredentialException(
resultData,
GetCredentialUnknownException() // Configure the proper exception
)
setResult(RESULT_OK, resultData)
finish()
Hãy tham khảo ứng dụng mẫu để xem ví dụ đầy đủ về cách trả về phản hồi thông tin đăng nhập theo bối cảnh.