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. ตั้งค่า
แอปตัวอย่างนี้ต้องมีการลิงก์ชิ้นงานดิจิทัลกับเว็บไซต์เพื่อให้ตัวจัดการข้อมูลเข้าสู่ระบบตรวจสอบการลิงก์และดำเนินการต่อ ดังนั้นรหัส RP ที่ใช้ในการตอบกลับจำลองจึงมาจากเซิร์ฟเวอร์ 3P จำลอง หากต้องการลองใช้การตอบกลับจำลองของคุณเอง ให้ลองเพิ่มโดเมนแอปและอย่าลืมทำการลิงก์ชิ้นงานดิจิทัลให้เสร็จสมบูรณ์ตามที่ระบุไว้ที่นี่
ใช้ debug.keystore เดียวกันกับที่กล่าวถึงในโปรเจ็กต์เพื่อสร้างตัวแปรการแก้ไขข้อบกพร่องและการเผยแพร่เพื่อยืนยันการลิงก์เนื้อหาดิจิทัลของชื่อแพ็กเกจและ SHA ในเซิร์ฟเวอร์จำลอง (ระบบดำเนินการให้คุณแล้วสำหรับแอปตัวอย่างใน build.gradle)
- โคลนที่เก็บนี้ในแล็ปท็อปจากสาขา credman_codelab: https://github.com/android/identity-samples/tree/credman_codelab
git clone -b credman_codelab https://github.com/android/identity-samples.git
- ไปที่โมดูล CredentialManager แล้วเปิดโปรเจ็กต์ใน Android Studio
มาดูสถานะเริ่มต้นของแอปกัน
หากต้องการดูว่าสถานะเริ่มต้นของแอปทำงานอย่างไร ให้ทำตามขั้นตอนต่อไปนี้
- เปิดแอป
- คุณจะเห็นหน้าจอหลักที่มีปุ่มลงชื่อสมัครใช้และลงชื่อเข้าใช้ ปุ่มเหล่านี้ยังไม่มีฟังก์ชันการทำงานใดๆ แต่เราจะเปิดใช้ฟังก์ชันการทำงานในส่วนที่จะกล่าวถึงต่อไป

3. เพิ่มความสามารถในการลงชื่อสมัครใช้โดยใช้พาสคีย์
เมื่อลงชื่อสมัครใช้บัญชีใหม่ในแอป Android ที่ใช้ Credential Manager API ผู้ใช้จะสร้างพาสคีย์สำหรับบัญชีของตนได้ ระบบจะจัดเก็บพาสคีย์นี้อย่างปลอดภัยไว้ในผู้ให้บริการข้อมูลเข้าสู่ระบบที่ผู้ใช้เลือก และจะใช้สำหรับการลงชื่อเข้าใช้ในอนาคตโดยไม่ต้องให้ผู้ใช้ป้อนรหัสผ่านทุกครั้ง
ตอนนี้คุณจะสร้างพาสคีย์และลงทะเบียนข้อมูลเข้าสู่ระบบของผู้ใช้โดยใช้ไบโอเมตริก/การล็อกหน้าจอ
ลงชื่อสมัครใช้ด้วยพาสคีย์
โค้ดภายใน CredentialManager/app/src/main/java/com/google/credentialmanager/sample/SignUpScreen.kt จะกำหนดช่องข้อความ "ชื่อผู้ใช้" และปุ่มเพื่อลงชื่อสมัครใช้ด้วยพาสคีย์

กำหนด Lambda createCredential() เพื่อใช้ใน ViewModel
ออบเจ็กต์ของเครื่องมือจัดการข้อมูลเข้าสู่ระบบต้องส่ง Activity ซึ่งเชื่อมโยงกับหน้าจอ อย่างไรก็ตาม โดยปกติแล้วการดำเนินการของเครื่องมือจัดการข้อมูลเข้าสู่ระบบจะทริกเกอร์ใน View Model และไม่แนะนำให้อ้างอิงกิจกรรมภายใน View Model ดังนั้น เราจึงกำหนดฟังก์ชันเครื่องมือจัดการข้อมูลเข้าสู่ระบบในไฟล์แยก CredentialManagerUtil.kt และอ้างอิงฟังก์ชันเหล่านั้นในหน้าจอที่เหมาะสม จากนั้นส่งไปยัง View Model เป็นการเรียกกลับผ่านฟังก์ชัน Lambda
ค้นหาความคิดเห็น TODO ในฟังก์ชัน createCredential() ใน CredentialManagerUtil.kt และเรียกใช้ฟังก์ชัน CredentialManager.create() ดังนี้
CredentialManagerUtil.kt
suspend fun createCredential(
activity: Activity,
request: CreateCredentialRequest
): CreateCredentialResponse {
TODO("Create a CredentialManager object and call createCredential() with a CreateCredentialRequest")
val credentialManager = CredentialManager.create(activity)
return credentialManager.createCredential(activity, request)
}
ส่งการท้าทายและการตอบกลับ JSON อื่นๆ ไปยังการเรียก createPasskey()
ก่อนที่จะสร้างพาสคีย์ คุณต้องขอข้อมูลที่จำเป็นจากเซิร์ฟเวอร์เพื่อส่งไปยัง Credential Manager API ในระหว่างการเรียก createCredential()
คุณมีคำตอบจำลองในชิ้นงานของโปรเจ็กต์อยู่แล้วชื่อ RegFromServer.txt ซึ่งจะแสดงผลพารามิเตอร์ที่จำเป็นในโค้ดแล็บนี้
- ในแอป ให้ไปที่
SignUpViewModel.ktค้นหาวิธีsignUpWithPasskeysที่คุณจะเขียนตรรกะสำหรับการสร้างพาสคีย์และอนุญาตให้ผู้ใช้เข้าถึง คุณดูวิธีการได้ในคลาสเดียวกัน - ค้นหาบล็อกความคิดเห็น
TODOถึงcreate a CreatePublicKeyCredentialRequest()แล้วแทนที่ด้วยโค้ดต่อไปนี้
SignUpViewModel.kt
TODO("Create a CreatePublicKeyCredentialRequest() with necessary registration json from server")
val request = CreatePublicKeyCredentialRequest(
jsonProvider.fetchRegistrationJson()
.replace("<userId>", getEncodedUserId())
.replace("<userName>", _username.value)
.replace("<userDisplayName>", _username.value)
.replace("<challenge>", getEncodedChallenge())
)
เมธอด jsonProvider.fetchRegistrationJsonFromServer() จะอ่านการตอบกลับ JSON ของเซิร์ฟเวอร์ที่จำลอง PublicKeyCredentialCreationOptions จากเนื้อหา และแสดงผล JSON การลงทะเบียนเพื่อส่งต่อขณะสร้างพาสคีย์ เราจะแทนที่ค่าตัวยึดตำแหน่งบางค่าด้วยรายการที่ผู้ใช้ป้อนจากแอปของเราและฟิลด์จำลองบางรายการ
- 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
พารามิเตอร์ | คำอธิบาย |
สตริงแบบสุ่มที่เซิร์ฟเวอร์สร้างขึ้นซึ่งมีเอนโทรปีเพียงพอที่จะทำให้การคาดเดาเป็นไปไม่ได้ โดยควรมีความยาวอย่างน้อย 16 ไบต์ คุณต้องระบุข้อมูลนี้ แต่จะไม่มีการใช้ในระหว่างการลงทะเบียนเว้นแต่จะทำการรับรอง | |
รหัสที่ไม่ซ้ำกันของผู้ใช้ ค่านี้ต้องไม่มีข้อมูลส่วนบุคคลที่ระบุตัวบุคคลนั้นได้ เช่น อีเมลหรือชื่อผู้ใช้ ค่าแบบสุ่มขนาด 16 ไบต์ที่สร้างขึ้นต่อบัญชีจะใช้งานได้ดี | |
ฟิลด์นี้ควรมีตัวระบุที่ไม่ซ้ำกันสำหรับบัญชีที่ผู้ใช้จะจดจำได้ เช่น อีเมลหรือชื่อผู้ใช้ ซึ่งจะแสดงในตัวเลือกบัญชี (หากใช้ชื่อผู้ใช้ ให้ใช้ค่าเดียวกับการตรวจสอบสิทธิ์ด้วยรหัสผ่าน) | |
ช่องนี้เป็นชื่อบัญชีที่ไม่บังคับซึ่งเรียกง่ายกว่า | |
เอนทิตีของบุคคลที่สามที่เชื่อถือได้จะสอดคล้องกับรายละเอียดแอปพลิเคชันของคุณ โดยมีแอตทริบิวต์ต่อไปนี้
| |
รายการอัลกอริทึมและประเภทคีย์ที่อนุญาต รายการนี้ต้องมีองค์ประกอบอย่างน้อย 1 รายการ | |
ผู้ใช้ที่พยายามลงทะเบียนอุปกรณ์อาจลงทะเบียนอุปกรณ์อื่นๆ ไว้แล้ว หากต้องการจำกัดการสร้างข้อมูลเข้าสู่ระบบหลายรายการสำหรับบัญชีเดียวกันในเครื่องมือตรวจสอบสิทธิ์เครื่องเดียว คุณก็สามารถเพิกเฉยต่ออุปกรณ์เหล่านี้ได้ สมาชิก | |
ระบุว่าควรแนบอุปกรณ์ในแพลตฟอร์มหรือไม่ หรือไม่จำเป็นต้องดำเนินการดังกล่าว ตั้งค่านี้เป็น | |
| ระบุค่า |
สร้างข้อมูลเข้าสู่ระบบ
- เมื่อสร้าง
CreatePublicKeyCredentialRequest()แล้ว คุณต้องเรียกใช้การเรียกcreateCredential()ด้วยคำขอที่สร้างขึ้น
SignUpViewModel.kt
try {
TODO("Call createCredential() with createPublicKeyCredentialRequest")
createCredential(request)
TODO("Complete the registration process after sending public key credential to your server and let the user in")
} catch (e: CreateCredentialException) {
handlePasskeyFailure(e)
}
- คุณจัดการระดับการมองเห็นของมุมมองที่แสดงผลและจัดการข้อยกเว้นหากคำขอไม่สำเร็จหรือล้มเหลวเนื่องจากเหตุผลบางประการ ระบบจะบันทึกข้อความแสดงข้อผิดพลาดที่นี่และแสดงในแอปในกล่องโต้ตอบข้อผิดพลาด คุณตรวจสอบบันทึกข้อผิดพลาดแบบเต็มได้ผ่าน Android Studio หรือคำสั่ง
adb debug

- สุดท้าย คุณต้องดำเนินการตามขั้นตอนการลงทะเบียนให้เสร็จสมบูรณ์ แอปจะส่งข้อมูลเข้าสู่ระบบคีย์สาธารณะไปยังเซิร์ฟเวอร์ซึ่งจะลงทะเบียนข้อมูลดังกล่าวกับผู้ใช้ปัจจุบัน
ในที่นี้เราใช้เซิร์ฟเวอร์จำลอง ดังนั้นเราจึงเพียงแค่ส่งคืนค่าเป็นจริงเพื่อระบุว่าเซิร์ฟเวอร์ได้บันทึกคีย์สาธารณะที่ลงทะเบียนไว้เพื่อวัตถุประสงค์ในการตรวจสอบสิทธิ์และการตรวจสอบในอนาคต ดูข้อมูลเพิ่มเติมเกี่ยวกับการลงทะเบียนพาสคีย์ฝั่งเซิร์ฟเวอร์สำหรับการติดตั้งใช้งานของคุณเองได้
ในเมธอด signUpWithPasskeys() ให้ค้นหาความคิดเห็นที่เกี่ยวข้องและแทนที่ด้วยโค้ดต่อไปนี้
SignUpViewModel.kt
try {
createCredential(request)
TODO("Complete the registration process after sending public key credential to your server and let the user in")
registerResponse()
DataProvider.setSignedInThroughPasskeys(true)
_navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = true))
} catch (e: CreateCredentialException) {
handlePasskeyFailure(e)
}
registerResponse()จะแสดงtrueซึ่งบ่งบอกว่าเซิร์ฟเวอร์จำลองได้บันทึกคีย์สาธารณะไว้ใช้ในอนาคตแล้ว- ตั้งค่าสถานะ
setSignedInThroughPasskeysเป็นtrue - เมื่อเข้าสู่ระบบแล้ว ให้เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอหลัก
PublicKeyCredential จริงอาจมีฟิลด์มากกว่านี้ ตัวอย่างของฟิลด์เหล่านี้แสดงอยู่ด้านล่าง
{
"id": String,
"rawId": String,
"type": "public-key",
"response": {
"clientDataJSON": String,
"attestationObject": String,
}
}
ตารางต่อไปนี้อธิบายพารามิเตอร์ที่สำคัญบางอย่างในออบเจ็กต์ PublicKeyCredential
พารามิเตอร์ | คำอธิบาย |
รหัสที่เข้ารหัส Base64URL ของพาสคีย์ที่สร้างขึ้น รหัสนี้ช่วยให้เบราว์เซอร์พิจารณาได้ว่ามีพาสคีย์ที่ตรงกันในอุปกรณ์หรือไม่เมื่อมีการตรวจสอบสิทธิ์ ค่านี้ต้องจัดเก็บไว้ในฐานข้อมูลในแบ็กเอนด์ | |
| |
ออบเจ็กต์ | |
ออบเจ็กต์การรับรองที่เข้ารหัส |
เรียกใช้แอป แล้วคุณจะคลิกปุ่มลงชื่อสมัครใช้ด้วยพาสคีย์และสร้างพาสคีย์ได้
4. บันทึกรหัสผ่านในผู้ให้บริการข้อมูลเข้าสู่ระบบ
ในแอปนี้ ภายในหน้าจอลงชื่อสมัครใช้ คุณมีตัวเลือกให้ลงชื่อสมัครใช้ด้วยชื่อผู้ใช้และรหัสผ่านเพื่อวัตถุประสงค์ในการสาธิตอยู่แล้ว
หากต้องการบันทึกข้อมูลเข้าสู่ระบบรหัสผ่านของผู้ใช้กับผู้ให้บริการรหัสผ่าน คุณจะต้องใช้ CreatePasswordRequest เพื่อส่งไปยัง createCredential() เพื่อบันทึกรหัสผ่าน
- ค้นหาเมธอด
signUpWithPassword()แล้วแทนที่ TODO ด้วยการเรียกcreatePasswordดังนี้
SignUpViewModel.kt
TODO("CreatePasswordRequest with entered username and password")
val passwordRequest = CreatePasswordRequest(_username.value, _password.value)
- จากนั้นสร้างข้อมูลเข้าสู่ระบบด้วยคำขอสร้างรหัสผ่าน และบันทึกข้อมูลเข้าสู่ระบบรหัสผ่านของผู้ใช้กับผู้ให้บริการรหัสผ่าน จากนั้นให้ผู้ใช้เข้าสู่ระบบ เราจะตรวจพบข้อยกเว้นที่เกิดขึ้นในโฟลว์นี้ในลักษณะทั่วไปมากขึ้น แทนที่ TODO ด้วยโค้ดต่อไปนี้
SignUpViewModel.kt
TODO("Create credential with created password request and log the user in")
try {
createCredential(passwordRequest)
simulateServerDelayAndLogIn()
} catch (e: Exception) {
val errorMessage = "Exception Message : " + e.message
Log.e("Auth", errorMessage)
_passwordCreationError.value = errorMessage
_isLoading.value = false
}
ตอนนี้คุณได้บันทึกข้อมูลเข้าสู่ระบบรหัสผ่านกับผู้ให้บริการรหัสผ่านของผู้ใช้เรียบร้อยแล้วเพื่อตรวจสอบสิทธิ์ด้วยรหัสผ่านได้ในคลิกเดียว
5. เพิ่มความสามารถในการตรวจสอบสิทธิ์ด้วยพาสคีย์หรือรหัสผ่าน
ตอนนี้คุณก็พร้อมที่จะใช้เป็นวิธีตรวจสอบสิทธิ์แอปของคุณอย่างปลอดภัยแล้ว

กำหนด Lambda getCredential() เพื่อใช้ใน ViewModel
เช่นเดียวกับก่อนหน้านี้ เราจะเรียกใช้ getCredential() ของเครื่องมือจัดการข้อมูลเข้าสู่ระบบในไฟล์แยก CredentialManagerUtil.kt เพื่อใช้อ้างอิงในหน้าจอที่เหมาะสมและส่งไปยัง View Model เป็นการเรียกกลับผ่านฟังก์ชัน Lambda
ค้นหาความคิดเห็น TODO ในฟังก์ชัน getCredential() ใน CredentialManagerUtil.kt และเรียกใช้ฟังก์ชัน CredentialManager.get() ดังนี้
suspend fun getCredential(
activity: Activity,
request: GetCredentialRequest
): GetCredentialResponse {
TODO("Create a CredentialManager object and call getCredential() with a GetCredentialRequest")
val credentialManager = CredentialManager.create(activity)
return credentialManager.getCredential(activity, request)
}
รับคำท้าและตัวเลือกอื่นๆ เพื่อส่งไปยังการเรียกใช้ getPasskey()
ก่อนขอให้ผู้ใช้ตรวจสอบสิทธิ์ คุณต้องขอพารามิเตอร์ที่จะส่งใน WebAuthn JSON จากเซิร์ฟเวอร์ รวมถึงการท้าทาย
คุณมีคำตอบจำลองในชิ้นงาน (AuthFromServer.txt) อยู่แล้ว ซึ่งจะแสดงพารามิเตอร์ดังกล่าวในโค้ดแล็บนี้
- ในแอป ให้ไปที่ SignInViewModel.kt แล้วค้นหาเมธอด
signInWithSavedCredentialsซึ่งคุณจะเขียนตรรกะสำหรับการตรวจสอบสิทธิ์ผ่านพาสคีย์หรือรหัสผ่านที่บันทึกไว้ และอนุญาตให้ผู้ใช้เข้าถึงได้ - สร้าง GetPublicKeyCredentialOption() โดยใช้พารามิเตอร์ที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบจากผู้ให้บริการข้อมูลเข้าสู่ระบบ
SignInViewModel.kt
TODO("Create a GetPublicKeyCredentialOption() with necessary authentication json from server")
val getPublicKeyCredentialOption =
GetPublicKeyCredentialOption(jsonProvider.fetchAuthJson(), null)
เมธอด fetchAuthJsonFromServer() จะอ่านการตอบกลับ JSON ของการตรวจสอบสิทธิ์จากเนื้อหาและส่งคืน JSON ของการตรวจสอบสิทธิ์เพื่อดึงพาสคีย์ทั้งหมดที่เชื่อมโยงกับบัญชีผู้ใช้นี้
พารามิเตอร์ที่ 2 ของ GetPublicKeyCredentialOption() คือ clientDataHash ซึ่งเป็นแฮชที่ใช้เพื่อยืนยันข้อมูลประจำตัวของ Relying Party ตั้งค่านี้ก็ต่อเมื่อคุณได้ตั้งค่า GetCredentialRequest.origin แล้ว สำหรับแอปตัวอย่าง ระบบจะตั้งค่านี้เป็น null
หมายเหตุ : เซิร์ฟเวอร์ของโค้ดแล็บนี้ออกแบบมาเพื่อแสดง JSON ที่คล้ายกับพจนานุกรม PublicKeyCredentialRequestOptions ที่ส่งไปยังการเรียก getCredential() ของ API ให้มากที่สุด ข้อมูลโค้ดต่อไปนี้มีตัวอย่างตัวเลือก 2-3 รายการที่คุณอาจได้รับในการตอบกลับจริง
{
"challenge": String,
"rpId": String,
"userVerification": "",
"timeout": 1800000
}
ตารางต่อไปนี้อธิบายพารามิเตอร์ที่สำคัญบางอย่างในออบเจ็กต์ PublicKeyCredentialRequestOptions
พารามิเตอร์ | คำอธิบาย |
คำท้าที่เซิร์ฟเวอร์สร้างขึ้นในออบเจ็กต์ | |
รหัส RP คือโดเมน เว็บไซต์ระบุได้ทั้งโดเมนหรือคำต่อท้ายที่จดทะเบียนได้ ค่านี้ต้องตรงกับพารามิเตอร์ |
- จากนั้นคุณต้องสร้างออบเจ็กต์
PasswordOption()เพื่อดึงรหัสผ่านที่บันทึกไว้ทั้งหมดในผู้ให้บริการรหัสผ่านผ่าน Credential Manager API สำหรับบัญชีผู้ใช้นี้ ในgetSavedCredentials()method ให้ค้นหา TODO แล้วแทนที่ด้วยข้อมูลต่อไปนี้
SigninViewModel.kt
TODO("Create a PasswordOption to retrieve all the associated user's password")
val getPasswordOption = GetPasswordOption()
รวมสิ่งเหล่านี้เป็น GetCredentialRequest
SigninViewModel.kt
TODO("Combine requests into a GetCredentialRequest")
val request = GetCredentialRequest(
listOf(
getPublicKeyCredentialOption,
getPasswordOption
)
)
รับข้อมูลเข้าสู่ระบบ
จากนั้นคุณต้องเรียกใช้คำขอ getCredential() โดยใช้ตัวเลือกทั้งหมดข้างต้นเพื่อดึงข้อมูลเข้าสู่ระบบที่เชื่อมโยง
SignInViewModel.kt
try {
TODO("Call getCredential() with required credential options")
val result = getCredential(request)
val data = when (result.credential) {
is PublicKeyCredential -> {
val cred = result.credential as PublicKeyCredential
DataProvider.setSignedInThroughPasskeys(true)
"Passkey: ${cred.authenticationResponseJson}"
}
is PasswordCredential -> {
val cred = result.credential as PasswordCredential
DataProvider.setSignedInThroughPasskeys(false)
"Got Password - User:${cred.id} Password: ${cred.password}"
}
is CustomCredential -> {
//If you are also using any external sign-in libraries, parse them here with the utility functions provided.
null
}
else -> null
}
TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
} catch (e: Exception) {
Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
_signInError.value =
"An error occurred while authenticating: " + e.message.toString()
} finally {
_isLoading.value = false
}
- คุณส่งข้อมูลที่จำเป็นไปยัง
getCredential()ซึ่งจะใช้รายการตัวเลือกข้อมูลเข้าสู่ระบบและบริบทกิจกรรมเพื่อแสดงตัวเลือกใน BottomSheet ในบริบทนั้น - เมื่อคำขอสำเร็จ คุณจะเห็น BottomSheet บนหน้าจอซึ่งแสดงข้อมูลเข้าสู่ระบบทั้งหมดที่สร้างขึ้นสำหรับบัญชีที่เชื่อมโยง
- ตอนนี้ผู้ใช้สามารถยืนยันตัวตนผ่านข้อมูลไบโอเมตริกหรือการล็อกหน้าจอ ฯลฯ เพื่อตรวจสอบสิทธิ์ของข้อมูลเข้าสู่ระบบที่เลือกได้แล้ว
- หากข้อมูลเข้าสู่ระบบที่เลือกเป็น
PublicKeyCredentialให้ตั้งค่าสถานะsetSignedInThroughPasskeysเป็นtrueมิเช่นนั้น ให้ตั้งค่าเป็นfalse
ข้อมูลโค้ดต่อไปนี้มีตัวอย่างออบเจ็กต์ PublicKeyCredential
{
"id": String
"rawId": String
"type": "public-key",
"response": {
"clientDataJSON": String
"authenticatorData": String
"signature": String
"userHandle": String
}
}
ตารางต่อไปนี้ไม่ได้ครอบคลุมทั้งหมด แต่มีพารามิเตอร์ที่สำคัญในออบเจ็กต์ PublicKeyCredential
พารามิเตอร์ | คำอธิบาย |
รหัสที่เข้ารหัส Base64URL ของข้อมูลเข้าสู่ระบบพาสคีย์ที่ได้รับการตรวจสอบสิทธิ์ | |
| |
ออบเจ็กต์ | |
ออบเจ็กต์ | |
ออบเจ็กต์ | |
|
- สุดท้าย คุณต้องดำเนินการตามกระบวนการตรวจสอบสิทธิ์ให้เสร็จสมบูรณ์ โดยปกติแล้ว หลังจากที่ผู้ใช้ทำการตรวจสอบสิทธิ์ด้วยพาสคีย์เสร็จสมบูรณ์ แอปจะส่งข้อมูลเข้าสู่ระบบคีย์สาธารณะที่มีการยืนยันการตรวจสอบสิทธิ์ไปยังเซิร์ฟเวอร์ ซึ่งจะยืนยันการยืนยันและตรวจสอบสิทธิ์ผู้ใช้
ในที่นี้ เราใช้เซิร์ฟเวอร์จำลอง ดังนั้นเราจึงเพียงแค่ส่งคืน true เพื่อระบุว่าเซิร์ฟเวอร์ได้ยืนยันการยืนยันแล้ว คุณอ่านข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบสิทธิ์พาสคีย์ฝั่งเซิร์ฟเวอร์สำหรับการติดตั้งใช้งานของคุณเองได้
ในเมธอด signInWithSavedCredentials() ให้ค้นหาความคิดเห็นที่เกี่ยวข้อง แล้วแทนที่ด้วยโค้ดต่อไปนี้
SignInViewModel.kt
TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
if (data != null) {
sendSignInResponseToServer()
_navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = DataProvider.isSignedInThroughPasskeys()))
}
sendSigninResponseToServer()จะแสดงผลเป็นจริง ซึ่งบ่งชี้ว่าเซิร์ฟเวอร์ (จำลอง) ได้ตรวจสอบคีย์สาธารณะเพื่อใช้ในอนาคตแล้ว- เมื่อเข้าสู่ระบบแล้ว ให้เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าจอหลัก
เรียกใช้แอป แล้วไปที่ลงชื่อเข้าใช้ > ลงชื่อเข้าใช้ด้วยพาสคีย์/รหัสผ่านที่บันทึกไว้ แล้วลองลงชื่อเข้าใช้โดยใช้ข้อมูลเข้าสู่ระบบที่บันทึกไว้
ลองใช้
คุณได้ติดตั้งใช้งานการสร้างพาสคีย์ การบันทึกรหัสผ่านในเครื่องมือจัดการข้อมูลเข้าสู่ระบบ และการตรวจสอบสิทธิ์ผ่านพาสคีย์หรือรหัสผ่านที่บันทึกไว้โดยใช้ Credential Manager API ในแอป Android
6. ยินดีด้วย
คุณทำ Codelab นี้เสร็จแล้ว หากต้องการดูโซลูชันสุดท้ายซึ่งมีอยู่ที่ https://github.com/android/identity-samples/tree/main/CredentialManager
หากมีคำถาม โปรดถามใน StackOverflow โดยใช้แท็ก passkey