Credential Manager – Verifier API

אימות של מסמכים דיגיטליים באפליקציות ל-Android יכול לשמש לאימות ולאישור של הזהות של משתמש (למשל תעודה מזהה ממשלתית), מאפיינים של המשתמש (למשל רישיון נהיגה, תואר אקדמי או מאפיינים כמו גיל או כתובת) או תרחישים אחרים שבהם צריך להנפיק ולאמת מסמך כדי לאשר את האותנטיות של ישות.

תקן התעודות הדיגיטליות הוא תקן ציבורי של W3C שמפרט איך לגשת לתעודות דיגיטליות שניתנות לאימות של משתמש מארנק דיגיטלי. התקן מיושם בתרחישי שימוש באינטרנט באמצעות W3C Credential Management API. ב-Android, נעשה שימוש ב-API של Credential Manager‏ DigitalCredential לאימות פרטי כניסה דיגיטליים.

הטמעה

כדי לאמת פרטי כניסה דיגיטליים בפרויקט Android, צריך לבצע את הפעולות הבאות:

  1. מוסיפים תלויות לסקריפט הבנייה של האפליקציה ומאתחלים מחלקה CredentialManager.
  2. יוצרים בקשה לפרטי כניסה דיגיטליים ומשתמשים בה כדי לאתחל את DigitalCredentialOption, ואז יוצרים את GetCredentialRequest.
  3. מפעילים את התהליך getCredential עם הבקשה שנוצרה כדי לקבל GetCredentialResponse או לטפל בחריגים שעלולים להתרחש. אחרי השליפה, צריך לאמת את התשובה.

הוספת יחסי תלות והפעלה ראשונית

מוסיפים את יחסי התלות הבאים לסקריפט ה-build של 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 כדי להציג למשתמש את האפשרויות הזמינות של פרטי הכניסה ולאסוף את הבחירה שלו. לאחר מכן, באפליקציית הארנק הדיגיטלי שבה נמצאת אפשרות האישורים שנבחרה יוצגו ממשקי משתמש לאיסוף הסכמה ולביצוע הפעולות הנדרשות ליצירת תגובה של אישור דיגיטלי.

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}")
    }
}