การแก้ไข 2024 ไตรมาสที่ 4: ดูวิธีลดความซับซ้อนของเส้นทางการตรวจสอบสิทธิ์โดยใช้ Credential Manager API ในแอป Android

1. ก่อนเริ่มต้น

โซลูชันการตรวจสอบสิทธิ์แบบดั้งเดิมก่อให้เกิดปัญหาด้านความปลอดภัยและความสามารถในการใช้งานหลายประการ

รหัสผ่านเป็นที่นิยมใช้กันมาก แต่...

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

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

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

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

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

  • ลงชื่อสมัครใช้ : ใช้พาสคีย์และรหัสผ่าน
  • ลงชื่อเข้าใช้ : ใช้พาสคีย์และรหัสผ่านที่บันทึกไว้

ข้อกำหนดเบื้องต้น

  • ทำความเข้าใจพื้นฐานเกี่ยวกับวิธีเรียกใช้แอปใน Android Studio
  • ทำความเข้าใจพื้นฐานเกี่ยวกับขั้นตอนการตรวจสอบสิทธิ์ในแอป Android
  • ทำความเข้าใจพื้นฐานเกี่ยวกับพาสคีย์

สิ่งที่คุณจะได้เรียนรู้

  • วิธีสร้างพาสคีย์
  • วิธีบันทึกรหัสผ่านในเครื่องมือจัดการรหัสผ่าน
  • วิธีตรวจสอบสิทธิ์ผู้ใช้ด้วยพาสคีย์หรือรหัสผ่านที่บันทึกไว้

สิ่งที่คุณต้องมี

อุปกรณ์ต่อไปนี้ต้องทำงานร่วมกัน

  • อุปกรณ์ Android ที่ใช้ Android 9 ขึ้นไป (สำหรับพาสคีย์) และ Android 4.4 ขึ้นไป(สำหรับการรับรองความถูกต้องด้วยรหัสผ่านผ่าน Credential Manager API)
  • อุปกรณ์ที่ควรมีเซ็นเซอร์ไบโอเมตริก
  • อย่าลืมลงทะเบียนข้อมูลไบโอเมตริก (หรือล็อกหน้าจอ)
  • เวอร์ชันปลั๊กอิน Kotlin : 1.8.10

2. ตั้งค่า

  1. โคลนที่เก็บนี้ในแล็ปท็อปจากสาขา credman_codelab : https://github.com/android/identity-samples/tree/credman_codelab
git clone -b credman_codelab https://github.com/android/identity-samples.git
  1. ไปที่โมดูล CredentialManager และเปิดโปรเจ็กต์ใน Android Studio

มาดูสถานะเริ่มต้นของแอปกัน

หากต้องการดูวิธีการทำงานของสถานะเริ่มต้นของแอป ให้ทำตามขั้นตอนต่อไปนี้

  1. เปิดแอป
  2. คุณจะเห็นหน้าจอหลักที่มีปุ่มลงชื่อสมัครใช้และลงชื่อเข้าใช้ ปุ่มเหล่านี้ยังไม่ทํางาน แต่เราจะเปิดใช้ฟังก์ชันการทํางานของปุ่มในส่วนถัดไป

7a6fe80f4cf877a8.jpeg

3. เพิ่มความสามารถในการลงชื่อสมัครใช้โดยใช้พาสคีย์

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

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

ลงชื่อสมัครใช้ด้วยพาสคีย์

โค้ดภายใน Credential Manager/app/main/java/SignUpFragment.kt จะกำหนดช่องข้อความ "username" และปุ่มลงชื่อสมัครใช้ด้วยพาสคีย์

1f4c50daa2551f1.jpeg

ส่งภารกิจและการตอบกลับ JSON อื่นๆ ไปยังการเรียก createPasskey()

ก่อนสร้างพาสคีย์ คุณต้องขอข้อมูลจากเซิร์ฟเวอร์เพื่อส่งไปยัง Credential Manager API ระหว่างการเรียกใช้ createCredential()

คุณมีคำตอบจำลองอยู่ในชิ้นงานของโปรเจ็กต์แล้ว ซึ่งเรียกว่า RegFromServer.txt ซึ่งจะแสดงผลพารามิเตอร์ที่จำเป็นในโค้ดแล็บนี้

  • ในแอป ให้ไปที่ SignUpFragment.kt แล้วค้นหาเมธอด signUpWithPasskeys ซึ่งคุณจะเขียนตรรกะในการสร้างพาสคีย์และอนุญาตให้ผู้ใช้เข้าสู่ระบบ คุณจะเห็นเมธอดนี้ในคลาสเดียวกัน
  • ตรวจสอบบล็อก else ที่มีความคิดเห็นเพื่อเรียก createPasskey() แล้วแทนที่ด้วยโค้ดต่อไปนี้

SignUpFragment.kt

//TODO : Call createPasskey() to signup with passkey

val data = createPasskey()

ระบบจะเรียกใช้เมธอดนี้เมื่อคุณกรอกชื่อผู้ใช้ที่ถูกต้องบนหน้าจอ

  • ในเมธอด createPasskey() คุณต้องสร้าง CreatePublicKeyCredentialRequest() ที่มีพารามิเตอร์ที่จำเป็นซึ่งแสดงผล

SignUpFragment.kt

//TODO create a CreatePublicKeyCredentialRequest() with necessary registration json from server

val request = CreatePublicKeyCredentialRequest(fetchRegistrationJsonFromServer())

เมธอด fetchRegistrationJsonFromServer() จะอ่านการตอบกลับ JSON PublicKeyCredentialCreationOptions ของเซิร์ฟเวอร์จำลองจากชิ้นงานและแสดงผล JSON การลงทะเบียนที่จะส่งไปขณะสร้างพาสคีย์

  • ค้นหาเมธอด fetchRegistrationJsonFromServer() แล้วแทนที่ TODO ด้วยโค้ดต่อไปนี้เพื่อแสดงผล JSON และนําคำสั่งแสดงผลสตริงว่างออก

SignUpFragment.kt

//TODO fetch registration mock response

val response = requireContext().readFromAsset("RegFromServer")

//Update userId,challenge, name and Display name in the mock
return response.replace("<userId>", getEncodedUserId())
   .replace("<userName>", binding.username.text.toString())
   .replace("<userDisplayName>", binding.username.text.toString())
   .replace("<challenge>", getEncodedChallenge())
  • JSON นี้ไม่สมบูรณ์และมี 4 ช่องที่ต้องแทนที่
  • UserId ต้องไม่ซ้ำกันเพื่อให้ผู้ใช้สร้างพาสคีย์ได้หลายรายการ (หากจำเป็น) แทนที่ <userId> ด้วยค่า userId ที่สร้างขึ้น
  • <challenge> จะต้องไม่ซ้ำกันด้วย คุณจึงจะสร้างภารกิจแบบสุ่มที่ไม่ซ้ำกันได้ วิธีการอยู่ในโค้ดของคุณอยู่แล้ว

การตอบกลับ PublicKeyCredentialCreationOptions ของเซิร์ฟเวอร์จริงอาจแสดงตัวเลือกเพิ่มเติม ตัวอย่างของช่องเหล่านี้มีดังนี้

{
  "challenge": String,
  "rp": {
    "name": String,
    "id": String
  },
  "user": {
    "id": String,
    "name": String,
    "displayName": String
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

ตารางต่อไปนี้อธิบายพารามิเตอร์ที่สําคัญบางรายการในออบเจ็กต์ PublicKeyCredentialCreationOptions

พารามิเตอร์

คำอธิบาย

challenge

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

user.id

รหัสที่ไม่ซ้ำกันของผู้ใช้ ค่านี้ต้องไม่มีข้อมูลที่ระบุตัวบุคคลได้ เช่น อีเมลหรือชื่อผู้ใช้ ค่าแบบสุ่ม 16 ไบต์ที่สร้างขึ้นต่อบัญชีจะทํางานได้ดี

user.name

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

user.displayName

ช่องนี้เป็นชื่อบัญชีที่เรียกง่ายขึ้นซึ่งไม่บังคับ

rp.id

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

  • name (ต้องระบุ): ชื่อแอปพลิเคชัน
  • ID (ไม่บังคับ): สอดคล้องกับโดเมนหรือโดเมนย่อย หากไม่มี ระบบจะใช้โดเมนปัจจุบัน
  • icon (ไม่บังคับ)

pubKeyCredParams

รายการอัลกอริทึมและประเภทคีย์ที่อนุญาต รายการนี้ต้องมีองค์ประกอบอย่างน้อย 1 รายการ

excludeCredentials

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

authenticatorSelection.authenticatorAttachment

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

residentKey

ระบุค่า required เพื่อสร้างพาสคีย์

สร้างข้อมูลเข้าสู่ระบบ

  1. เมื่อสร้าง CreatePublicKeyCredentialRequest() แล้ว คุณต้องเรียกใช้การเรียก createCredential() ด้วยคําขอที่สร้างไว้

SignUpFragment.kt

//TODO call createCredential() with createPublicKeyCredentialRequest

try {
   response = credentialManager.createCredential(
       requireActivity(),
       request
   ) as CreatePublicKeyCredentialResponse
} catch (e: CreateCredentialException) {
   configureProgress(View.INVISIBLE)
   handlePasskeyFailure(e)
}
  • คุณส่งข้อมูลที่จําเป็นไปยัง createCredential()
  • เมื่อส่งคำขอสำเร็จแล้ว คุณจะเห็นหน้าจอด้านล่างแจ้งให้สร้างพาสคีย์
  • ตอนนี้ผู้ใช้สามารถยืนยันตัวตนผ่านข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ ฯลฯ
  • คุณจัดการการแสดงผลที่แสดงผลแล้วและจัดการข้อยกเว้นหากคําขอไม่สําเร็จหรือประสบปัญหาเนื่องจากเหตุผลบางอย่าง ข้อความแสดงข้อผิดพลาดจะบันทึกไว้ที่นี่และแสดงในแอปในกล่องโต้ตอบข้อผิดพลาด คุณสามารถตรวจสอบบันทึกข้อผิดพลาดฉบับเต็มผ่าน Android Studio หรือคำสั่ง adb debug

1ea8ace66135de1e.png

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

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

ในเมธอด signUpWithPasskeys() ให้ค้นหาความคิดเห็นที่เกี่ยวข้อง แล้วแทนที่ด้วยโค้ดต่อไปนี้

SignUpFragment.kt

//TODO : complete the registration process after sending public key credential to your server and let the user in

data?.let {
   registerResponse()
   DataProvider.setSignedInThroughPasskeys(true)
   listener.showHome()
}
  • registerResponse() จะแสดงผลเป็น true ซึ่งระบุว่าเซิร์ฟเวอร์จำลองได้บันทึกคีย์สาธารณะไว้ใช้ในอนาคต
  • ตั้งค่าสถานะ setSignedInThroughPasskeys เป็น true
  • เมื่อเข้าสู่ระบบแล้ว ให้เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอหลัก

PublicKeyCredential จริงอาจมีฟิลด์มากกว่านี้ ตัวอย่างของช่องเหล่านี้แสดงอยู่ด้านล่าง

{
  "id": String,
  "rawId": String,
  "type": "public-key",
  "response": {
    "clientDataJSON": String,
    "attestationObject": String,
  }
}

ตารางต่อไปนี้อธิบายพารามิเตอร์ที่สําคัญบางรายการในออบเจ็กต์ PublicKeyCredential

พารามิเตอร์

คำอธิบาย

id

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

rawId

รหัสข้อมูลเข้าสู่ระบบเวอร์ชันออบเจ็กต์ ArrayBuffer

response.clientDataJSON

ออบเจ็กต์ ArrayBuffer ที่เข้ารหัสข้อมูลไคลเอ็นต์

response.attestationObject

ออบเจ็กต์การรับรองที่เข้ารหัส ArrayBuffer ซึ่งประกอบด้วยข้อมูลสำคัญ เช่น รหัส RP, Flag และคีย์สาธารณะ

เรียกใช้แอป แล้วคุณจะคลิกปุ่มลงชื่อสมัครใช้ด้วยพาสคีย์และสร้างพาสคีย์ได้

4. บันทึกรหัสผ่านในผู้ให้บริการข้อมูลเข้าสู่ระบบ

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

หากต้องการบันทึกข้อมูลเข้าสู่ระบบรหัสผ่านของผู้ใช้กับผู้ให้บริการรหัสผ่าน คุณจะใช้ CreatePasswordRequest เพื่อส่งไปยัง createCredential() เพื่อบันทึกรหัสผ่าน

  • ค้นหาเมธอด signUpWithPassword() แล้วแทนที่ TODO ด้วยการเรียกใช้ createPassword ดังนี้

SignUpFragment.kt

//TODO : Save the user credential password with their password provider

createPassword()
  • ในเมธอด createPassword() คุณต้องสร้างคำขอรหัสผ่านเช่นนี้ โดยแทนที่ TODO ด้วยโค้ดต่อไปนี้

SignUpFragment.kt

//TODO : CreatePasswordRequest with entered username and password

val request = CreatePasswordRequest(
   binding.username.text.toString(),
   binding.password.text.toString()
)
  • ถัดไป ภายในเมธอด createPassword() ให้สร้างข้อมูลเข้าสู่ระบบที่มีคำขอสร้างรหัสผ่าน และบันทึกข้อมูลเข้าสู่ระบบรหัสผ่านของผู้ใช้ด้วยผู้ให้บริการรหัสผ่าน แทนที่ TODO ด้วยโค้ดต่อไปนี้

SignUpFragment.kt

//TODO : Create credential with created password request


try {
   credentialManager.createCredential(requireActivity(), request) as CreatePasswordResponse
} catch (e: Exception) {
   Log.e("Auth", " Exception Message : " + e.message)
}
  • ตอนนี้คุณได้บันทึกข้อมูลเข้าสู่ระบบด้วยรหัสผ่านไว้กับผู้ให้บริการรหัสผ่านของผู้ใช้เพื่อตรวจสอบสิทธิ์ด้วยรหัสผ่านด้วยการแตะเพียงครั้งเดียวเรียบร้อยแล้ว

5. เพิ่มความสามารถในการตรวจสอบสิทธิ์ด้วยพาสคีย์หรือรหัสผ่าน

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

76e81460b26f9798.png

รับภารกิจและตัวเลือกอื่นๆ เพื่อส่งไปยังการเรียก getPasskey()

คุณต้องขอพารามิเตอร์เพื่อส่งใน WebAuthn JSON จากเซิร์ฟเวอร์ รวมถึงคำขอแจ้งให้ดำเนินการ (Challenge) ก่อนขอให้ผู้ใช้ตรวจสอบสิทธิ์

คุณมีคำตอบจำลองอยู่ในชิ้นงาน (AuthFromServer.txt) ซึ่งแสดงผลพารามิเตอร์ดังกล่าวในโค้ดแล็บนี้อยู่แล้ว

  • ในแอป ให้ไปที่ SignInFragment.kt แล้วค้นหาเมธอด signInWithSavedCredentials ที่คุณจะใช้เขียนตรรกะสำหรับการตรวจสอบสิทธิ์ผ่านพาสคีย์หรือรหัสผ่านที่บันทึกไว้และอนุญาตให้ผู้ใช้เข้าสู่ระบบ
  • ตรวจสอบบล็อก else ที่มีความคิดเห็นเพื่อเรียก createPasskey() แล้วแทนที่ด้วยโค้ดต่อไปนี้

SignInFragment.kt

//TODO : Call getSavedCredentials() method to signin using passkey/password

val data = getSavedCredentials()
  • ในเมธอด getSavedCredentials() คุณต้องสร้าง GetPublicKeyCredentialOption() ที่มีพารามิเตอร์ที่จำเป็นในการรับข้อมูลเข้าสู่ระบบจากผู้ให้บริการข้อมูลเข้าสู่ระบบ

SigninFragment.kt

//TODO create a GetPublicKeyCredentialOption() with necessary registration json from server

val getPublicKeyCredentialOption =
   GetPublicKeyCredentialOption(fetchAuthJsonFromServer(), null)

เมธอด fetchAuthJsonFromServer() จะอ่านการตอบกลับ JSON การตรวจสอบสิทธิ์จากชิ้นงานและแสดงผล JSON การตรวจสอบสิทธิ์เพื่อดึงข้อมูลพาสคีย์ทั้งหมดที่เชื่อมโยงกับบัญชีผู้ใช้นี้

พารามิเตอร์ที่ 2 ของ GetPublicKeyCredentialOption() คือ clientDataHash ซึ่งเป็นแฮชที่ใช้เพื่อยืนยันตัวตนของฝ่ายที่เชื่อถือ ตั้งค่านี้เฉพาะในกรณีที่คุณตั้งค่า GetCredentialRequest.origin สําหรับแอปตัวอย่าง จะมีการกําหนดค่านี้เป็น null

  • ค้นหาเมธอด fetchAuthJsonFromServer() แล้วแทนที่ TODO ด้วยโค้ดต่อไปนี้เพื่อแสดงผล JSON และนําออกคำสั่งแสดงผลสตริงว่าง

SignInFragment.kt

//TODO fetch authentication mock json

return requireContext().readFromAsset("AuthFromServer")

หมายเหตุ : เซิร์ฟเวอร์ของโค้ดแล็บนี้ออกแบบมาเพื่อแสดงผล JSON ที่คล้ายกับพจนานุกรม PublicKeyCredentialRequestOptions ที่ส่งไปยังการเรียก getCredential() ของ API มากที่สุด ข้อมูลโค้ดต่อไปนี้มีตัวอย่างตัวเลือก 2-3 รายการที่คุณอาจได้รับในการตอบกลับจริง

{
  "challenge": String,
  "rpId": String,
  "userVerification": "",
  "timeout": 1800000
}

ตารางต่อไปนี้อธิบายพารามิเตอร์ที่สําคัญบางรายการในออบเจ็กต์ PublicKeyCredentialRequestOptions

พารามิเตอร์

คำอธิบาย

challenge

ภารกิจที่เซิร์ฟเวอร์สร้างขึ้นในออบเจ็กต์ ArrayBuffer ซึ่งจำเป็นต้องทำเพื่อป้องกันการโจมตีแบบส่งซ้ำ อย่าตอบคำถามเดิมซ้ำ 2 ครั้ง โปรดพิจารณาว่านี่คือโทเค็น CSRF

rpId

รหัส RP คือโดเมน เว็บไซต์จะระบุโดเมนหรือนามสกุลที่จดทะเบียนได้ก็ได้ ค่านี้ต้องตรงกับพารามิเตอร์ rp.id ที่ใช้เมื่อสร้างพาสคีย์

  • ถัดไปคุณต้องสร้างออบเจ็กต์ PasswordOption() เพื่อดึงข้อมูลรหัสผ่านที่บันทึกไว้ทั้งหมดในผู้ให้บริการรหัสผ่านผ่าน Credential Manager API สำหรับบัญชีผู้ใช้นี้ ในเมธอด getSavedCredentials() ให้ค้นหา TODO แล้วแทนที่ด้วยข้อความต่อไปนี้

SigninFragment.kt

//TODO create a PasswordOption to retrieve all the associated user's password

val getPasswordOption = GetPasswordOption()

รับข้อมูลเข้าสู่ระบบ

  • ถัดไป คุณต้องเรียกใช้คําขอ getCredential() พร้อมตัวเลือกทั้งหมดข้างต้นเพื่อดึงข้อมูลเข้าสู่ระบบที่เชื่อมโยง

SignInFragment.kt

//TODO call getCredential() with required credential options

val result = try {
   credentialManager.getCredential(
       requireActivity(),
       GetCredentialRequest(
           listOf(
               getPublicKeyCredentialOption,
               getPasswordOption
           )
     )
   )
} catch (e: Exception) {
   configureViews(View.INVISIBLE, true)
   Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
   activity?.showErrorAlert(
       "An error occurred while authenticating through saved credentials. Check logs for additional details"
   )
   return null
}

if (result.credential is PublicKeyCredential) {
   val cred = result.credential as PublicKeyCredential
   DataProvider.setSignedInThroughPasskeys(true)
   return "Passkey: ${cred.authenticationResponseJson}"
}
if (result.credential is PasswordCredential) {
   val cred = result.credential as PasswordCredential
   DataProvider.setSignedInThroughPasskeys(false)
   return "Got Password - User:${cred.id} Password: ${cred.password}"
}
if (result.credential is CustomCredential) {
   //If you are also using any external sign-in libraries, parse them here with the utility functions provided.
}

  • คุณส่งข้อมูลที่จําเป็นไปยัง getCredential() ซึ่งจะนํารายการตัวเลือกข้อมูลเข้าสู่ระบบและบริบทกิจกรรมมาแสดงผลตัวเลือกใน Bottom Sheet ในบริบทนั้น
  • เมื่อส่งคำขอสำเร็จแล้ว คุณจะเห็นหน้าจอด้านล่างแสดงข้อมูลเข้าสู่ระบบทั้งหมดที่สร้างไว้สำหรับบัญชีที่เชื่อมโยง
  • ตอนนี้ผู้ใช้สามารถยืนยันตัวตนผ่านข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ ฯลฯ เพื่อตรวจสอบสิทธิ์ข้อมูลเข้าสู่ระบบที่เลือก
  • หากข้อมูลเข้าสู่ระบบที่เลือกคือ PublicKeyCredential ให้ตั้งค่า Flag setSignedInThroughPasskeys เป็น true มิเช่นนั้น ให้ตั้งค่าเป็น false

ข้อมูลโค้ดต่อไปนี้มีตัวอย่างออบเจ็กต์ PublicKeyCredential

{
  "id": String
  "rawId": String
  "type": "public-key",
  "response": {
    "clientDataJSON": String
    "authenticatorData": String
    "signature": String
    "userHandle": String
  }
}

ตารางต่อไปนี้ไม่ได้ครอบคลุมทั้งหมด แต่มีพารามิเตอร์ที่สําคัญในแออบเจ็กต์ PublicKeyCredential

พารามิเตอร์

คำอธิบาย

id

รหัสที่เข้ารหัส Base64URL ของข้อมูลเข้าสู่ระบบพาสคีย์ที่ตรวจสอบสิทธิ์แล้ว

rawId

รหัสข้อมูลเข้าสู่ระบบเวอร์ชันออบเจ็กต์ ArrayBuffer

response.clientDataJSON

ออบเจ็กต์ ArrayBuffer ของข้อมูลลูกค้า ช่องนี้มีข้อมูล เช่น คำถามและต้นทางที่เซิร์ฟเวอร์ RP ต้องยืนยัน

response.authenticatorData

ออบเจ็กต์ ArrayBuffer ของข้อมูลโปรแกรมตรวจสอบสิทธิ์ ช่องนี้มีข้อมูล เช่น รหัส RP

response.signature

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

response.userHandle

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

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

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

ภายในเมธอด signInWithSavedCredentials() ให้ค้นหาความคิดเห็นที่เกี่ยวข้อง แล้วแทนที่ด้วยโค้ดต่อไปนี้

SignInFragment.kt

//TODO : complete the authentication process after validating the public key credential to your server and let the user in.

data?.let {
   sendSignInResponseToServer()
   listener.showHome()
}
  • sendSigninResponseToServer() จะแสดงผลเป็น "จริง" ซึ่งบ่งบอกว่าเซิร์ฟเวอร์ (จำลอง) ได้ตรวจสอบคีย์สาธารณะเพื่อใช้ในอนาคตแล้ว
  • เมื่อเข้าสู่ระบบแล้ว ให้เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอหลัก

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

ลองใช้

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

6. ยินดีด้วย

คุณทำ Codelab นี้เสร็จแล้ว หากต้องการตรวจสอบโซลูชันขั้นสุดท้าย โปรดไปที่ https://github.com/android/identity-samples/tree/main/CredentialManager

หากมีคำถาม โปรดถามใน StackOverflow โดยใช้แท็ก passkey

ดูข้อมูลเพิ่มเติม