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

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

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

รหัสผ่านมีการใช้กันอย่างแพร่หลาย แต่...

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

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

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

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

ใน Codelab นี้ คุณจะได้เรียนรู้วิธีลงชื่อสมัครใช้ด้วยพาสคีย์และรหัสผ่านโดยใช้ 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
  2. ไปที่โมดูลCredentialManager และเปิดโปรเจ็กต์ใน Android Studio

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

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

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

8c0019ff9011950a.jpeg

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

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

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

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

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

ภายในเครื่องมือจัดการข้อมูลเข้าสู่ระบบ -> แอป -> หลัก -> Java -> SignUpFragment.kt คุณจะเห็นฟิลด์ข้อความ "username" และปุ่มสำหรับลงชื่อสมัครใช้ด้วยพาสคีย์

dcc5c529b310f2fb.jpeg

ตอบคำถามและการตอบสนอง JSON อื่นๆ เพื่อเรียก createPasskey()

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

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

  • ในแอป ให้ไปที่เมธอด SignUpFragment.kt, Find, signUpWithPasskeys ซึ่งคุณจะเขียนตรรกะในการสร้างพาสคีย์และอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้ คุณจะพบเมธอดได้ในชั้นเรียนเดียวกัน
  • ตรวจสอบบล็อกอื่นด้วยความคิดเห็นเพื่อเรียกใช้ 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 การลงทะเบียนจากเนื้อหา และส่ง JSON การลงทะเบียนที่จะส่งไปในขณะที่สร้างพาสคีย์

  • ค้นหาเมธอด tagRegistrationJsonFromServer() และแทนที่ 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 การลงทะเบียนจากเนื้อหา
  • ต้องแทนที่ JSON นี้ 4 ช่อง
  • UserId ต้องไม่ซ้ำกันเพื่อให้ผู้ใช้สร้างพาสคีย์หลายรายการได้ (หากจำเป็น) คุณแทนที่ <userId> ที่สร้างรหัสผู้ใช้ขึ้นมา
  • &lt;challenge&gt; ต้องไม่ซ้ำกัน คุณจึงจะสร้างเกมท้าทายที่มีเอกลักษณ์แบบสุ่มได้ มีเมธอดในโค้ดของคุณอยู่แล้ว

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

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

บุคคลที่พึ่งพามีความเกี่ยวข้องกับรายละเอียดในการสมัครของคุณ โดยต้องการ :

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

pubKeyCredParams

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

excludeCredentials

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

authenticatorSelection.authenticatorAttachment

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

residentKey

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

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

  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()
  • เมื่อคำขอเสร็จสมบูรณ์แล้ว คุณจะเห็น Bottom Sheet บนหน้าจอที่แจ้งให้สร้างพาสคีย์
  • ตอนนี้ผู้ใช้สามารถยืนยันตัวตนด้วยข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ ฯลฯ
  • คุณจะจัดการระดับการมองเห็นที่แสดงผลได้ และจัดการข้อยกเว้นในกรณีที่คำขอไม่สำเร็จหรือไม่สำเร็จด้วยเหตุผลบางอย่าง ข้อความแสดงข้อผิดพลาดจะได้รับการบันทึกและแสดงข้อความในแอปในกล่องโต้ตอบข้อผิดพลาด คุณสามารถตรวจสอบบันทึกข้อผิดพลาดทั้งหมดได้ผ่าน Android Studio หรือคำสั่งแก้ไขข้อบกพร่อง adb

93022cb87c00f1fc.png

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

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

ภายในเมธอด 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 แสดงค่าที่เป็นจริงซึ่งระบุ (จำลอง) ได้บันทึกคีย์สาธารณะไว้สำหรับการใช้งานในอนาคต
  • คุณตั้งค่าตัวบ่งชี้ SigningInThroughPasskeys เป็น "จริง" ซึ่งแสดงว่าคุณกำลังเข้าสู่ระบบผ่านพาสคีย์
  • เมื่อเข้าสู่ระบบแล้ว คุณจะเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอหลัก

ข้อมูลโค้ดต่อไปนี้มีตัวเลือกตัวอย่างที่คุณควรจะได้รับ

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

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

พารามิเตอร์

คำอธิบาย

id

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

rawId

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

response.clientDataJSON

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

response.attestationObject

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

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

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

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

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

629001f4a778d4fb.png

รับโจทย์และตัวเลือกอื่นๆ ที่จะผ่านเพื่อเรียก getPasskey()

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

คุณมีการตอบสนองจำลองใน Asset(AuthFromServer.txt) แล้ว ซึ่งจะแสดงพารามิเตอร์ดังกล่าวใน Codelab นี้

  • ในแอป ให้ไปที่ SignInFragment.kt จากนั้นค้นหาเมธอด signInWithSavedCredentials ที่คุณจะเขียนตรรกะสำหรับการตรวจสอบสิทธิ์ผ่านพาสคีย์หรือรหัสผ่านที่บันทึกไว้ แล้วให้ผู้ใช้ใน
  • ตรวจสอบบล็อกอื่นด้วยความคิดเห็นเพื่อเรียกใช้ 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 : clientDataHash - แฮชที่ใช้เพื่อยืนยันข้อมูลประจำตัวของบุคคลที่เกี่ยวข้อง ซึ่งตั้งค่าเฉพาะเมื่อคุณตั้งค่า GetCredentialRequest.origin สำหรับแอปตัวอย่าง ค่านี้จะเป็นค่าว่าง

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

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

SignInFragment.kt

//TODO fetch authentication mock json

return requireContext().readFromAsset("AuthFromServer")

หมายเหตุ : เซิร์ฟเวอร์ของ Codelab นี้ได้รับการออกแบบมาให้แสดงผล 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 ในบริบทดังกล่าว
  • เมื่อคําขอเสร็จสมบูรณ์แล้ว คุณจะเห็น Bottom Sheet บนหน้าจอที่แสดงข้อมูลเข้าสู่ระบบทั้งหมดที่สร้างขึ้นสําหรับบัญชีที่เชื่อมโยง
  • ตอนนี้ผู้ใช้สามารถยืนยันตัวตนได้ผ่านข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ ฯลฯ เพื่อตรวจสอบสิทธิ์ของข้อมูลเข้าสู่ระบบที่เลือก
  • คุณตั้งค่าตัวบ่งชี้ SigningInThroughPasskeys เป็น "จริง" ซึ่งแสดงว่าคุณกำลังเข้าสู่ระบบผ่านพาสคีย์ หากไม่เลือก จะเป็นเท็จ
  • คุณจะจัดการระดับการมองเห็นที่แสดงผลได้ และจัดการข้อยกเว้นในกรณีที่คำขอไม่สำเร็จหรือไม่สำเร็จด้วยเหตุผลบางอย่าง ข้อความแสดงข้อผิดพลาดจะได้รับการบันทึกและแสดงข้อความในแอปในกล่องโต้ตอบข้อผิดพลาด คุณสามารถตรวจสอบบันทึกข้อผิดพลาดทั้งหมดได้ผ่าน Android Studio หรือคำสั่งแก้ไขข้อบกพร่อง adb
  • ขั้นตอนสุดท้าย คุณต้องดำเนินการลงทะเบียนให้เสร็จสมบูรณ์โดยการส่งข้อมูลรับรองคีย์สาธารณะไปยังเซิร์ฟเวอร์และให้ผู้ใช้ป้อน แอปจะได้รับออบเจ็กต์ข้อมูลเข้าสู่ระบบที่มีคีย์สาธารณะซึ่งคุณส่งไปยังเซิร์ฟเวอร์เพื่อตรวจสอบสิทธิ์ผ่านพาสคีย์ได้

ในหน้านี้ เราใช้เซิร์ฟเวอร์จำลอง เราจึงแสดงค่า 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() แสดงผล true ที่ระบุ (เซิร์ฟเวอร์จำลอง) ได้ตรวจสอบคีย์สาธารณะสำหรับการใช้งานในอนาคต
  • เมื่อเข้าสู่ระบบแล้ว คุณจะเปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอหลัก

ข้อมูลโค้ดต่อไปนี้มีตัวอย่างออบเจ็กต์ 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 ของข้อมูล Authenticator ช่องนี้มีข้อมูล เช่น รหัส RP

response.signature

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

response.userHandle

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

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

ลองใช้

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

6. ยินดีด้วย

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

หากมีข้อสงสัย ให้ถามได้ใน StackOverflow โดยใช้แท็ก passkey

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