ลงชื่อเข้าใช้ด้วยพาสคีย์

คู่มือนี้จะอธิบายต่อเกี่ยวกับการติดตั้งใช้งานการใช้พาสคีย์เพื่อการตรวจสอบสิทธิ์ ก่อนที่ผู้ใช้จะลงชื่อเข้าใช้ด้วยพาสคีย์ได้ คุณต้องทำตาม วิธีการในสร้างพาสคีย์ให้เสร็จสมบูรณ์ด้วย

หากต้องการตรวจสอบสิทธิ์ด้วยพาสคีย์ คุณต้องเรียกข้อมูลตัวเลือกที่จำเป็นเพื่อ เรียกคีย์สาธารณะจากเซิร์ฟเวอร์แอปก่อน แล้วเรียกใช้ Credential Manager API เพื่อเรียกคีย์สาธารณะ จากนั้นจัดการการตอบกลับการลงชื่อเข้าใช้ อย่างเหมาะสม

ภาพรวม

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

หากต้องการดึงตัวเลือกพาสคีย์และรหัสผ่านทั้งหมดที่เชื่อมโยงกับบัญชีของผู้ใช้ ให้ทำตามขั้นตอนต่อไปนี้

  1. รับตัวเลือกคำขอข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์: ส่งคำขอจากแอปไปยังเซิร์ฟเวอร์การตรวจสอบสิทธิ์เพื่อเริ่มกระบวนการลงชื่อเข้าใช้ด้วยพาสคีย์ จากเซิร์ฟเวอร์ ให้ส่งตัวเลือกที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ รวมถึงการท้าทายที่ไม่ซ้ำกัน
  2. สร้างออบเจ็กต์ที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ: ห่อหุ้ม ตัวเลือกที่เซิร์ฟเวอร์ส่งมาในออบเจ็กต์ GetPublicKeyCredentialOption
  3. (ไม่บังคับ) เตรียม getCredential: ใน Android 14 ขึ้นไป คุณสามารถ ลดเวลาในการตอบสนองโดยแสดงตัวเลือกบัญชีโดยใช้เมธอด prepareGetCredential() ก่อนเรียกใช้ getCredential()
  4. เปิดโฟลว์การลงชื่อเข้าใช้: เรียกใช้เมธอด getCredential() เพื่อลงชื่อเข้าใช้ ผู้ใช้
  5. จัดการการตอบกลับ: จัดการการตอบกลับที่เป็นไปได้แต่ละรายการของข้อมูลเข้าสู่ระบบ
  6. จัดการข้อยกเว้น: ตรวจสอบว่าคุณจัดการข้อยกเว้น อย่างเหมาะสม

1. รับตัวเลือกคำขอข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์

ขอตัวเลือกที่จำเป็นต่อการรับข้อมูลเข้าสู่ระบบคีย์สาธารณะจากเซิร์ฟเวอร์ รวมถึง challenge ซึ่งไม่ซ้ำกันสำหรับการพยายามลงชื่อเข้าใช้แต่ละครั้ง ดูข้อมูลเพิ่มเติมเกี่ยวกับการติดตั้งใช้งานฝั่งเซิร์ฟเวอร์ได้ที่สร้าง ชาเลนจ์และสร้างตัวเลือกคำขอข้อมูลเข้าสู่ระบบ

ตัวเลือกจะมีลักษณะคล้ายกับตัวเลือกต่อไปนี้

{
  "challenge": "<your app challenge>",
  "allowCredentials": [],
  "rpId": "<your app server domain>"
}

ดูข้อมูลเพิ่มเติมเกี่ยวกับช่องได้ในบล็อกโพสต์เรื่องการลงชื่อเข้าใช้ด้วย พาสคีย์

2. สร้างออบเจ็กต์ที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ

ในแอป ให้ใช้ตัวเลือกเพื่อสร้างออบเจ็กต์ GetPublicKeyCredentialOption ในตัวอย่างต่อไปนี้ requestJson แสดงถึงตัวเลือกที่เซิร์ฟเวอร์ส่งมา

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

จากนั้นห่อ GetPublicKeyCredentialOption ในออบเจ็กต์ 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. ไม่บังคับ: ลดเวลาในการตอบสนองของการลงชื่อเข้าใช้

ใน Android 14 ขึ้นไป คุณสามารถลดเวลาในการตอบสนองเมื่อแสดงตัวเลือกบัญชี ได้โดยใช้วิธี prepareGetCredential() ก่อนเรียกใช้ getCredential()

เมธอด prepareGetCredential() จะแสดงผลออบเจ็กต์ PrepareGetCredentialResponse ซึ่งแคชไว้ ซึ่งจะช่วยให้เมธอด getCredential() ในขั้นตอนถัดไปแสดงตัวเลือกบัญชี พร้อมข้อมูลที่แคชไว้

coroutineScope {
    val response = credentialManager.prepareGetCredential(
        GetCredentialRequest(
            listOf(
                // Include all the sign-in options that your app supports
                getPublicKeyCredentialOption, 
                getPasswordOption
            )
        )
    )
}

4. เปิดโฟลว์การลงชื่อเข้าใช้

เรียกใช้เมธอด getCredential() เพื่อแสดงตัวเลือกบัญชีแก่ผู้ใช้ ใช้ข้อมูลโค้ดต่อไปนี้เป็นข้อมูลอ้างอิงสำหรับวิธีเปิดโฟลว์การลงชื่อเข้าใช้

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. จัดการคำตอบ

จัดการการตอบกลับ ซึ่งอาจมีออบเจ็กต์ข้อมูลเข้าสู่ระบบประเภทต่างๆ อย่างใดอย่างหนึ่ง

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 ที่ได้จากการตรวจสอบสิทธิ์คือการยืนยันที่ลงชื่อ แล้ว ซึ่งมีโครงสร้างดังนี้

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

คุณต้องยืนยันข้อมูลเข้าสู่ระบบในเซิร์ฟเวอร์ ดูข้อมูลเพิ่มเติมได้ที่ยืนยันและ ลงชื่อเข้าใช้ผู้ใช้

6. จัดการข้อยกเว้น

คุณควรจัดการข้อยกเว้นของคลาสย่อยทั้งหมดของ GetCredentialException ดูวิธีจัดการข้อยกเว้นแต่ละรายการได้ในคู่มือการแก้ปัญหา

coroutineScope {
    try {
        result = credentialManager.getCredential(
            context = activityContext,
            request = credentialRequest
        )
    } catch (e: GetCredentialException) {
        Log.e("CredentialManager", "No credential available", e)
    }
}

ขั้นตอนถัดไป