สร้างพาสคีย์

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

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

ระบบจะจัดเก็บพาสคีย์ไว้ในผู้ให้บริการข้อมูลเข้าสู่ระบบ และจัดเก็บคีย์สาธารณะไว้ในเซิร์ฟเวอร์ของแอป
รูปที่ 1: การสร้างพาสคีย์

สิ่งที่ต้องมีก่อน

ตรวจสอบว่าคุณได้ตั้งค่า Digital Asset Links และกำหนดเป้าหมายเป็น อุปกรณ์ที่ใช้ Android 9 (API ระดับ 28) ขึ้นไป

ภาพรวม

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

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

1. เพิ่มการอ้างอิงไปยังแอป

เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในไฟล์ build.gradle ของโมดูลแอป

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.6.0-beta03")
    implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta03")
}

Groovy

dependencies {
    implementation "androidx.credentials:credentials:1.6.0-beta03"
    implementation "androidx.credentials:credentials-play-services-auth:1.6.0-beta03"
}

2. สร้างอินสแตนซ์ของ Credential Manager

ใช้บริบทของแอปหรือกิจกรรมเพื่อสร้างออบเจ็กต์ CredentialManager

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)

3. รับตัวเลือกการสร้างข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์แอป

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

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

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

ข้อมูลโค้ดต่อไปนี้แสดงโครงสร้างของตัวเลือกการสร้างคีย์สาธารณะที่เซิร์ฟเวอร์แอปส่ง

{
  "challenge": "<base64url-encoded challenge>",
  "rp": {
    "name": "<relying party name>",
    "id": "<relying party host name>"
  },
  "user": {
    "id": "<base64url-encoded user ID>",
    "name": "<user name>",
    "displayName": "<user display name>"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    }
  ],
  "attestation": "none",
  "excludeCredentials": [
    {
        "id": "<base64url-encoded credential ID to exclude>", 
        "type": "public-key"
    }
  ],
  "authenticatorSelection": {
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

ฟิลด์หลักในตัวเลือกการสร้างคีย์สาธารณะมีดังนี้

  • challenge: สตริงแบบสุ่มที่เซิร์ฟเวอร์สร้างขึ้นซึ่งใช้เพื่อป้องกันการโจมตีแบบเล่นซ้ำ
  • rp: รายละเอียดเกี่ยวกับแอป
    • rp.name: ชื่อแอป
    • rp.id: โดเมนหรือโดเมนย่อยของแอป
  • user: รายละเอียดเกี่ยวกับผู้ใช้
    • id: รหัสที่ไม่ซ้ำกันของผู้ใช้ ค่านี้ต้องไม่มีข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้ เช่น อีเมลหรือชื่อผู้ใช้ คุณ สามารถใช้ค่าแบบสุ่มขนาด 16 ไบต์ได้
    • name: ตัวระบุที่ไม่ซ้ำกันสำหรับบัญชีที่ผู้ใช้จะจดจำได้ เช่น อีเมลหรือชื่อผู้ใช้ ชื่อนี้จะ แสดงในตัวเลือกบัญชี หากใช้ชื่อผู้ใช้ ให้ใช้ค่าเดียวกับที่ใช้ในการตรวจสอบสิทธิ์ด้วยรหัสผ่าน
    • displayName: ชื่อบัญชีที่เลือกได้และเป็นมิตรกับผู้ใช้ซึ่งมีไว้สำหรับ แสดงในตัวเลือกบัญชี
  • authenticatorSelection: รายละเอียดเกี่ยวกับอุปกรณ์ที่จะใช้ในการ ตรวจสอบสิทธิ์

    • authenticatorAttachment: ระบุ เครื่องมือตรวจสอบสิทธิ์ที่ต้องการ ค่าที่เป็นไปได้มีดังนี้ - platform: ค่านี้ใช้สำหรับเครื่องมือตรวจสอบสิทธิ์ที่สร้างไว้ใน อุปกรณ์ของผู้ใช้ เช่น เซ็นเซอร์ลายนิ้วมือ - cross-platform: ค่านี้ใช้สำหรับอุปกรณ์ที่โรมมิ่ง เช่น คีย์ความปลอดภัย โดยปกติแล้วจะไม่ใช้ในบริบทของพาสคีย์ - ไม่ได้ระบุ (แนะนำ): การไม่ระบุค่านี้ จะช่วยให้ผู้ใช้มีความยืดหยุ่นในการสร้างพาสคีย์ในอุปกรณ์ที่ต้องการ ในกรณีส่วนใหญ่ การปล่อยให้พารามิเตอร์ ไม่ระบุเป็นตัวเลือกที่ดีที่สุด
      • requireResidentKey: หากต้องการสร้างพาสคีย์ ให้ตั้งค่าของฟิลด์ Boolean นี้เป็น true
      • residentKey: หากต้องการสร้างพาสคีย์ ให้ตั้งค่าเป็น required
      • userVerification: ใช้เพื่อระบุข้อกำหนดสำหรับการยืนยันตัวตนผู้ใช้ ในระหว่างการลงทะเบียนพาสคีย์ ค่าที่เป็นไปได้มีดังนี้ - preferred: ใช้ค่านี้หากคุณให้ความสำคัญกับประสบการณ์ของผู้ใช้มากกว่าการปกป้อง เช่น ในสภาพแวดล้อมที่การยืนยันตัวตนของผู้ใช้ทำให้เกิดอุปสรรคมากกว่าการปกป้อง - required: ใช้ค่านี้หากต้องเรียกใช้วิธีการยืนยันตัวตนผู้ใช้ ที่มีในอุปกรณ์ - discouraged: ใช้ค่านี้หากไม่แนะนำให้ใช้วิธีการยืนยันผู้ใช้
        ดูข้อมูลเพิ่มเติมเกี่ยวกับ userVerificationได้ที่ ข้อมูลเจาะลึกเกี่ยวกับการยืนยันผู้ใช้
  • excludeCredentials: แสดงรหัสข้อมูลเข้าสู่ระบบในอาร์เรย์เพื่อ ป้องกันการสร้างพาสคีย์ที่ซ้ำกันหากมีพาสคีย์ที่มีผู้ให้บริการข้อมูลเข้าสู่ระบบเดียวกันอยู่แล้ว

4. ขอพาสคีย์

หลังจากแยกวิเคราะห์ตัวเลือกการสร้างคีย์สาธารณะฝั่งเซิร์ฟเวอร์แล้ว ให้สร้าง พาสคีย์โดยการรวมตัวเลือกเหล่านี้ไว้ในออบเจ็กต์ CreatePublicKeyCredentialRequest และเรียกใช้ createCredential()

createPublicKeyCredentialRequest ประกอบด้วยข้อมูลต่อไปนี้

  • requestJson: ตัวเลือกการสร้างข้อมูลเข้าสู่ระบบที่เซิร์ฟเวอร์แอปส่งมา
  • preferImmediatelyAvailableCredentials: นี่คือฟิลด์บูลีนที่ไม่บังคับ ซึ่งกำหนดว่าจะใช้เฉพาะข้อมูลเข้าสู่ระบบที่พร้อมใช้งานในเครื่องหรือข้อมูลเข้าสู่ระบบที่ซิงค์กับผู้ให้บริการข้อมูลเข้าสู่ระบบเพื่อดำเนินการตามคำขอหรือไม่ แทนที่จะใช้ข้อมูลเข้าสู่ระบบจากคีย์ความปลอดภัยหรือขั้นตอนไฮบริด การใช้งานที่เป็นไปได้มีดังนี้
    • false (ค่าเริ่มต้น): ใช้ค่านี้หากการเรียก Credential Manager ถูกทริกเกอร์โดยการดำเนินการของผู้ใช้โดยชัดแจ้ง
    • true: ใช้ค่านี้หากมีการเรียกใช้ตัวจัดการข้อมูลเข้าสู่ระบบตามโอกาส เช่น เมื่อเปิดแอปเป็นครั้งแรก
      หากคุณตั้งค่าเป็น true และไม่มีข้อมูลเข้าสู่ระบบที่พร้อมใช้งานทันที ตัวจัดการข้อมูลเข้าสู่ระบบจะไม่แสดง UI ใดๆ และคำขอจะล้มเหลวทันที โดยจะแสดง NoCredentialException สำหรับคำขอ get และ CreateCredentialNoCreateOptionException สำหรับคำขอ create
  • origin: ระบบจะตั้งค่าช่องนี้โดยอัตโนมัติสำหรับแอป Android สำหรับเบราว์เซอร์และแอปที่มีสิทธิ์คล้ายกันซึ่งต้องตั้งค่า origin โปรดดูเรียกใช้ Credential Manager ในนามของบุคคลที่สามสำหรับแอปที่มีสิทธิ์
  • isConditional: ช่องนี้เป็นช่องที่ไม่บังคับ ซึ่งค่าเริ่มต้นคือ false เมื่อตั้งค่านี้เป็น true และหากผู้ใช้ไม่มีพาสคีย์ คุณจะสร้างพาสคีย์ให้ผู้ใช้โดยอัตโนมัติในครั้งถัดไปที่ผู้ใช้ลงชื่อเข้าใช้ด้วยรหัสผ่านที่บันทึกไว้ ระบบจะจัดเก็บพาสคีย์ไว้ในผู้ให้บริการข้อมูลเข้าสู่ระบบของผู้ใช้ ฟีเจอร์การสร้างแบบมีเงื่อนไขต้องใช้ androidx.credentials เวอร์ชันล่าสุด

การเรียกใช้ฟังก์ชัน createCredential() จะเปิด UI ชีตด้านล่างในตัวของ Credential Manager ซึ่งจะแจ้งให้ผู้ใช้ใช้พาสคีย์และเลือกผู้ให้บริการข้อมูลเข้าสู่ระบบและบัญชีสำหรับจัดเก็บ อย่างไรก็ตาม หากตั้งค่า isConditional เป็น true UI ของ Bottom Sheet จะไม่แสดง และระบบจะสร้างพาสคีย์โดยอัตโนมัติ

5. จัดการคำตอบ

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

การตอบกลับหลังจากเรียกใช้ createCredential() สำเร็จแล้วคือออบเจ็กต์ PublicKeyCredential

PublicKeyCredential มีลักษณะดังนี้

{
  "id": "<identifier>",
  "type": "public-key",
  "rawId": "<identifier>",
  "response": {
    "clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
    "attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
  },
  "authenticatorAttachment": "platform"
}

ในแอปไคลเอ็นต์ ให้แปลงออบเจ็กต์เป็นอนุกรมแล้วส่งไปยังเซิร์ฟเวอร์แอป

เพิ่มโค้ดเพื่อจัดการความล้มเหลวดังที่แสดงในข้อมูลโค้ดต่อไปนี้

fun handleFailure(e: CreateCredentialException) {
    when (e) {
        is CreatePublicKeyCredentialDomException -> {
            // Handle the passkey DOM errors thrown according to the
            // WebAuthn spec.
        }
        is CreateCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to register the credential.
        }
        is CreateCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is CreateCredentialProviderConfigurationException -> {
            // Your app is missing the provider configuration dependency.
            // Most likely, you're missing the
            // "credentials-play-services-auth" module.
        }
        is CreateCredentialCustomException -> {
            // You have encountered an error from a 3rd-party SDK. If you
            // make 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.name}")
    }
}

6. ยืนยันและบันทึกคีย์สาธารณะในเซิร์ฟเวอร์แอป

ในเซิร์ฟเวอร์แอป คุณต้องยืนยันข้อมูลเข้าสู่ระบบคีย์สาธารณะ แล้วบันทึก คีย์สาธารณะ

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

วิธีรับลายนิ้วมือ SHA 256 ของแอป

  1. พิมพ์ใบรับรองการลงนามของแอปเวอร์ชันที่เผยแพร่โดยเรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล

    keytool -list -keystore <path-to-apk-signing-keystore>
    

    ในคำตอบ ให้ระบุลายนิ้วมือ SHA 256 ของใบรับรองการลงนาม ซึ่งระบุเป็น Certificate fingerprints block : SHA256

  2. เข้ารหัสลายนิ้วมือ SHA256 ด้วยการเข้ารหัส base64url ตัวอย่าง Python นี้ แสดงวิธีเข้ารหัสลายนิ้วมืออย่างถูกต้อง

    import binascii
    import base64
    fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint
    print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
    
  3. เพิ่ม android:apk-key-hash: ที่จุดเริ่มต้นของเอาต์พุตจากขั้นตอนก่อนหน้า เพื่อให้คุณได้ผลลัพธ์ที่คล้ายกับต่อไปนี้

    android:apk-key-hash:<encoded SHA 256 fingerprint>
    

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

7. แจ้งเตือนผู้ใช้

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

ปรับปรุงประสบการณ์ของผู้ใช้

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

เพิ่มฟังก์ชันการทำงานเพื่อกู้คืนข้อมูลเข้าสู่ระบบในอุปกรณ์เครื่องใหม่

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

ระงับการป้อนข้อความอัตโนมัติในช่องข้อมูลเข้าสู่ระบบ (ไม่บังคับ)

สำหรับหน้าจอแอปที่คาดว่าผู้ใช้จะใช้ UI ของชีตด้านล่างของเครื่องมือจัดการข้อมูลเข้าสู่ระบบเพื่อการตรวจสอบสิทธิ์ ให้เพิ่มแอตทริบิวต์ isCredential ลงในช่องชื่อผู้ใช้ และรหัสผ่าน ซึ่งจะป้องกันไม่ให้กล่องโต้ตอบการป้อนข้อความอัตโนมัติ (FillDialog และ SaveDialog) ทับซ้อนกับ UI ของ Bottom Sheet ของ Credential Manager

ระบบรองรับแอตทริบิวต์ isCredential ใน Android 14 ขึ้นไป

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

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:isCredential="true" />

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