Android 應用程式中的數位憑證驗證功能,可用於驗證及授權使用者身分 (例如政府核發的身分證件)、使用者相關屬性 (例如駕照、學位或年齡/地址等屬性),或在其他情境中核發及驗證憑證,以確認實體的真實性。
數位憑證是 W3C 公開標準,用於指定如何從數位錢包存取使用者的可驗證數位憑證,並透過 W3C 憑證管理 API 實作,適用於網路應用情境。在 Android 裝置上,Credential Manager 的 DigitalCredential API 用於驗證數位憑證。
實作
如要在 Android 專案中驗證數位憑證,請按照下列步驟操作:
- 在應用程式的建構指令碼中加入依附元件,並初始化
CredentialManager類別。 - 建構數位憑證要求,並用來初始化
DigitalCredentialOption,然後建構GetCredentialRequest。 - 使用建構的要求啟動
getCredential流程,即可接收成功的GetCredentialResponse或處理可能發生的任何例外狀況。成功擷取後,請驗證回應。
新增依附元件並初始化
將下列依附元件新增至 Gradle 建構指令碼:
dependencies {
implementation("androidx.credentials:credentials:1.6.0-beta01")
implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta01")
}
接著,初始化 CredentialManager 類別的執行個體。
val credentialManager = CredentialManager.create(context)
建構數位憑證要求
建構數位憑證要求,並用來初始化 DigitalCredentialOption。
// The request in the JSON format to conform with
// the JSON-ified Credential Manager - Verifier API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
GetDigitalCredentialOption(requestJson = requestJson)
// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
listOf(digitalCredentialOption)
)
以下是 OpenId4Vp 要求的範例。如需完整參考資料,請參閱這個網站。
{
"requests": [
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "OD8eP8BYfr0zyhgq4QCVEGN3m7C1Ht_No9H5fG5KJFk",
"dcql_query": {
"credentials": [
{
"id": "cred1",
"format": "mso_mdoc",
"meta": {
"doctype_value": "org.iso.18013.5.1.mDL"
},
"claims": [
{
"path": [
"org.iso.18013.5.1",
"family_name"
]
},
{
"path": [
"org.iso.18013.5.1",
"given_name"
]
},
{
"path": [
"org.iso.18013.5.1",
"age_over_21"
]
}
]
}
]
}
}
}
]
}
取得憑證
使用建構的要求啟動 getCredential 流程。如果要求成功,您會收到 GetCredentialResponse,如果要求失敗,則會收到 GetCredentialException。
getCredential 流程會觸發 Android 系統對話方塊,向使用者顯示可用的憑證選項,並收集使用者的選擇。接著,含有所選憑證選項的錢包應用程式會顯示 UI,收集同意聲明並執行產生數位憑證回應所需的動作。
coroutineScope.launch {
try {
val result = credentialManager.getCredential(
context = activityContext,
request = getCredRequest
)
verifyResult(result)
} catch (e : GetCredentialException) {
handleFailure(e)
}
}
// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
val credential = result.credential
when (credential) {
is DigitalCredential -> {
val responseJson = credential.credentialJson
validateResponseOnServer(responseJson)
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential ${credential.type}")
}
}
}
// Handle failure.
fun handleFailure(e: GetCredentialException) {
when (e) {
is GetCredentialCancellationException -> {
// The user intentionally canceled the operation and chose not
// to share the credential.
}
is GetCredentialInterruptedException -> {
// Retry-able error. Consider retrying the call.
}
is NoCredentialException -> {
// No credential was available.
}
is CreateCredentialUnknownException -> {
// An unknown, usually unexpected, error has occurred. Check the
// message error for any additional debugging information.
}
is CreateCredentialCustomException -> {
// You have encountered a custom error thrown by the wallet.
// If you made 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}")
}
}