ก่อนที่ผู้ใช้จะสามารถตรวจสอบสิทธิ์ด้วยพาสคีย์ได้ แอปของคุณต้องลงทะเบียน หรือสร้างพาสคีย์สำหรับบัญชีของผู้ใช้ก่อน
หากต้องการสร้างพาสคีย์ ให้รับรายละเอียดที่จำเป็นในการสร้างพาสคีย์จากเซิร์ฟเวอร์แอป แล้วเรียกใช้ Credential Manager API ซึ่งจะส่งกลับคู่คีย์สาธารณะและ ส่วนตัว ระบบจะจัดเก็บคีย์ส่วนตัวที่ส่งคืนไว้ในผู้ให้บริการข้อมูลเข้าสู่ระบบ เช่น เครื่องมือจัดการรหัสผ่านบน Google เป็นพาสคีย์ คีย์สาธารณะจะจัดเก็บไว้ในเซิร์ฟเวอร์แอป
สิ่งที่ต้องมีก่อน
ตรวจสอบว่าคุณได้ตั้งค่า Digital Asset Links และกำหนดเป้าหมายเป็น อุปกรณ์ที่ใช้ Android 9 (API ระดับ 28) ขึ้นไป
ภาพรวม
คู่มือนี้มุ่งเน้นการเปลี่ยนแปลงที่จำเป็นในแอปไคลเอ็นต์ของบุคคลที่สาม เพื่อสร้างพาสคีย์ และให้ภาพรวมโดยย่อของการติดตั้งใช้งานเซิร์ฟเวอร์ของแอปบุคคลที่สาม ดูข้อมูลเพิ่มเติมเกี่ยวกับการผสานรวมฝั่งเซิร์ฟเวอร์ได้ที่การลงทะเบียนพาสคีย์ฝั่งเซิร์ฟเวอร์
- เพิ่มทรัพยากร Dependency ลงในแอป: เพิ่มไลบรารี Credential Manager ที่จำเป็น
- สร้างอินสแตนซ์ของเครื่องมือจัดการข้อมูลเข้าสู่ระบบ: สร้างอินสแตนซ์ของเครื่องมือจัดการข้อมูลเข้าสู่ระบบ
- รับตัวเลือกการสร้างข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์แอป: จากเซิร์ฟเวอร์แอป ให้ส่งรายละเอียดที่จำเป็นต่อการสร้างพาสคีย์ไปยังแอปไคลเอ็นต์ เช่น ข้อมูลเกี่ยวกับแอป ผู้ใช้ รวมถึง
challengeและฟิลด์อื่นๆ - ขอพาสคีย์: ในแอป ให้ใช้รายละเอียดที่ได้รับจากเซิร์ฟเวอร์แอปเพื่อสร้างออบเจ็กต์
GetPublicKeyCredentialOptionและใช้ออบเจ็กต์นี้เพื่อเรียกใช้เมธอดcredentialManager.getCredential()เพื่อสร้างพาสคีย์ - จัดการการตอบกลับการสร้างพาสคีย์: เมื่อได้รับข้อมูลเข้าสู่ระบบในแอปไคลเอ็นต์ คุณต้องเข้ารหัส จัดรูปแบบ และส่งคีย์สาธารณะไปยังเซิร์ฟเวอร์แอป นอกจากนี้ คุณยังต้องจัดการข้อยกเว้นแต่ละรายการที่อาจเกิดขึ้นในกรณีที่มีการสร้างพาสคีย์ด้วย
- ยืนยันและบันทึกคีย์สาธารณะในเซิร์ฟเวอร์: ทำขั้นตอนฝั่งเซิร์ฟเวอร์ให้เสร็จสมบูรณ์ เพื่อยืนยันแหล่งที่มาของข้อมูลเข้าสู่ระบบ แล้วบันทึกคีย์สาธารณะ
- แจ้งให้ผู้ใช้ทราบ: แจ้งให้ผู้ใช้ทราบว่าระบบได้สร้างพาสคีย์แล้ว
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นี้เป็นtrueresidentKey: หากต้องการสร้างพาสคีย์ ให้ตั้งค่าเป็นrequireduserVerification: ใช้เพื่อระบุข้อกำหนดสำหรับการยืนยันตัวตนผู้ใช้ ในระหว่างการลงทะเบียนพาสคีย์ ค่าที่เป็นไปได้มีดังนี้ -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 ของแอป
พิมพ์ใบรับรองการลงนามของแอปเวอร์ชันที่เผยแพร่โดยเรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล
keytool -list -keystore <path-to-apk-signing-keystore>ในคำตอบ ให้ระบุลายนิ้วมือ SHA 256 ของใบรับรองการลงนาม ซึ่งระบุเป็น
Certificate fingerprints block:SHA256เข้ารหัสลายนิ้วมือ 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('=', ''))เพิ่ม
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" />