ขอข้อมูลเข้าสู่ระบบดิจิทัล

การยืนยันข้อมูลเข้าสู่ระบบดิจิทัลภายในแอป Android สามารถใช้เพื่อตรวจสอบสิทธิ์และให้สิทธิ์ตัวตนของผู้ใช้ (เช่น บัตรประจำตัวที่ออกโดยหน่วยงานราชการ) คุณสมบัติเกี่ยวกับผู้ใช้รายนั้น (เช่น ใบขับขี่ วุฒิการศึกษา หรือแอตทริบิวต์ต่างๆ เช่น อายุหรือที่อยู่) หรือสถานการณ์อื่นๆ ที่จำเป็นต้องออกและยืนยันข้อมูลเข้าสู่ระบบเพื่อยืนยันความถูกต้องของเอนทิตี

Verifier API รองรับใน Android 9 (ระดับ API 28) ขึ้นไป

การใช้งาน

หากต้องการยืนยันข้อมูลเข้าสู่ระบบดิจิทัลในโปรเจ็กต์ Android ให้ทำดังนี้

  1. เพิ่มทรัพยากร Dependency ลงในสคริปต์บิลด์ของแอปและเริ่มต้นคลาส CredentialManager
  2. สร้างคำขอข้อมูลเข้าสู่ระบบดิจิทัลและใช้เพื่อเริ่มต้น DigitalCredentialOption ตามด้วยการสร้าง GetCredentialRequest
  3. เปิดใช้งานขั้นตอน getCredential ด้วยคำขอที่สร้างขึ้นเพื่อรับ GetCredentialResponse ที่สำเร็จหรือจัดการข้อยกเว้นที่อาจเกิดขึ้น เมื่อดึงข้อมูลสำเร็จแล้ว ให้ตรวจสอบความถูกต้องของการตอบกลับ

เพิ่มทรัพยากร Dependency และเริ่มต้นใช้งาน

เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในสคริปต์บิลด์ 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)
)

ตัวอย่างต่อไปนี้แสดงคำขอ OpenId4Vp1 ดูรายละเอียดเกี่ยวกับช่องในคำขอนี้ได้ที่เอกสารประกอบของ OpenID

{
  "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 เพื่อแสดงตัวเลือกข้อมูลเข้าสู่ระบบที่ผู้ใช้มีอยู่และรวบรวมตัวเลือกของผู้ใช้ จากนั้น แอป Wallet ที่มีตัวเลือกข้อมูลเข้าสู่ระบบที่เลือกจะแสดง 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.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}
รูปภาพแสดงตัวเลือกข้อมูลเข้าสู่ระบบดิจิทัลที่แสดงเมื่อเรียกใช้ getCredential
รูปที่ 1 ตัวเลือกข้อมูลเข้าสู่ระบบดิจิทัลที่แสดงเมื่อเรียกใช้ getCredential

คำขอข้อมูลเข้าสู่ระบบหลายรายการที่ยืดหยุ่น

นอกจากนี้ Digital Credentials API ยังรองรับการขอข้อมูลเข้าสู่ระบบหลายประเภทพร้อมกันโดยใช้ OpenID4VP ด้วย

  • คำขอพร้อมกัน: ขอข้อมูลเข้าสู่ระบบหลายรายการในธุรกรรมของผู้ใช้รายการเดียว ตัวอย่างเช่น แอปการเดินทางสามารถขอบอร์ดดิ้งพาสและบัตรประจำตัวที่ออกโดยหน่วยงานราชการพร้อมกันได้ ซึ่งช่วยให้ผู้ใช้ตรวจสอบและให้ความยินยอมสำหรับทั้ง 2 รายการได้ด้วยการแตะเพียงครั้งเดียว
  • การดำเนินการที่ยืดหยุ่น: ยอมรับข้อมูลเข้าสู่ระบบหรือผู้ออกข้อมูลเข้าสู่ระบบประเภทใดประเภทหนึ่งจากหลายประเภท ตัวอย่างเช่น ขั้นตอนการยืนยันอายุสามารถยอมรับใบขับขี่หรือหนังสือเดินทางได้ ซึ่งช่วยให้ผู้ใช้ดำเนินการตามคำขอได้โดยใช้ข้อมูลเข้าสู่ระบบที่จัดเก็บไว้ในที่เก็บข้อมูลของตน

ต่อไปนี้เป็นตัวอย่างการขอข้อมูลเข้าสู่ระบบหลายรายการในคำขอเดียว

{
  "credentials": [
    {
      "id": "gov_id1",
      "format": "mso_mdoc",
      "meta": {
        "doctype_value": "org.iso.18013.5.1.mDL"
      },
      "claims": [
        {
          "path": [
            "org.iso.18013.5.1",
            "age_over_21"
          ]
        }
      ]
    },
    {
      "id": "boarding_pass1",
      "format": "dc+sd-jwt",
      "meta": {
        "vct_values": [
          "https://credentials.example.airline/boarding-pass"
        ]
      },
      "claims": [
        {
          "path": [
            "flight_number"
          ]
        },
        {
          "path": [
            "seat"
          ]
        }
      ]
    }
  ]
}
รูปภาพแสดงตัวเลือกข้อมูลเข้าสู่ระบบดิจิทัลที่แสดงเมื่อเรียกใช้ข้อมูลเข้าสู่ระบบหลายประเภท
รูปที่ 1 ตัวเลือกเอกสารรับรองดิจิทัลที่แสดงเมื่อเรียกใช้เอกสารรับรองหลายประเภท

จัดการการตอบกลับ

หลังจากส่งคำขอข้อมูลเข้าสู่ระบบแล้ว ให้จัดการ GetCredentialResponse ที่แสดงผลจาก CredentialManager

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