คู่มือนี้จะอธิบายต่อเกี่ยวกับการใช้พาสคีย์เพื่อการตรวจสอบสิทธิ์ ก่อนที่ผู้ใช้จะลงชื่อเข้าใช้ด้วยพาสคีย์ได้ คุณต้องทำตาม วิธีการในหัวข้อสร้างพาสคีย์ด้วย
หากต้องการตรวจสอบสิทธิ์ด้วยพาสคีย์ คุณต้องดึงข้อมูลตัวเลือกที่จำเป็นในการ ดึงข้อมูลคีย์สาธารณะจาก เซิร์ฟเวอร์แอปก่อน แล้วเรียกใช้ Credential Manager API เพื่อดึงข้อมูลคีย์สาธารณะ จากนั้นจัดการการตอบกลับการลงชื่อเข้าใช้อย่างเหมาะสม
ภาพรวม
คู่มือนี้จะเน้นที่การเปลี่ยนแปลงที่จำเป็นในแอปไคลเอ็นต์เพื่อลงชื่อเข้าใช้ผู้ใช้ด้วยพาสคีย์ และให้ภาพรวมคร่าวๆ เกี่ยวกับการติดตั้งใช้งานฝั่งเซิร์ฟเวอร์แอป ดูข้อมูลเพิ่มเติมเกี่ยวกับการผสานรวมฝั่งเซิร์ฟเวอร์ได้ที่การตรวจสอบสิทธิ์พาสคีย์ ฝั่งเซิร์ฟเวอร์
หากต้องการดึงข้อมูลตัวเลือกพาสคีย์และรหัสผ่านทั้งหมดที่เชื่อมโยงกับบัญชีของผู้ใช้ ให้ทำตามขั้นตอนต่อไปนี้
- **รับตัวเลือกคำขอข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์**: ส่งคำขอจาก แอปไปยังเซิร์ฟเวอร์การตรวจสอบสิทธิ์เพื่อเริ่มกระบวนการลงชื่อเข้าใช้ด้วยพาสคีย์ จากเซิร์ฟเวอร์ ให้ส่งตัวเลือกที่จำเป็นในการรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ รวมถึงการท้าทายที่ไม่ซ้ำกัน
- สร้างออบเจ็กต์ที่จำเป็นในการรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ: ห่อ
ตัวเลือกที่เซิร์ฟเวอร์ส่งมาในออบเจ็กต์
GetPublicKeyCredentialOption - (ไม่บังคับ) เตรียม getCredential: ใน Android 14 ขึ้นไป คุณสามารถ
ลดเวลาในการตอบสนองได้โดยการแสดงตัวเลือกบัญชีโดยใช้วิธี
prepareGetCredential()ก่อนที่จะเรียกใช้getCredential() - เปิดใช้ขั้นตอนการลงชื่อเข้าใช้: เรียกใช้วิธี
getCredential()เพื่อลงชื่อเข้าใช้ ผู้ใช้ - **จัดการการตอบกลับ**: จัดการการตอบกลับข้อมูลเข้าสู่ระบบที่เป็นไปได้แต่ละรายการ
- จัดการข้อยกเว้น: ตรวจสอบว่าคุณจัดการข้อยกเว้น อย่างเหมาะสม
รับตัวเลือกคำขอข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์
ขอตัวเลือกที่จำเป็นในการรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ รวมถึง challenge จากเซิร์ฟเวอร์ ซึ่งจะไม่ซ้ำกันสำหรับการพยายามลงชื่อเข้าใช้แต่ละครั้ง ดูข้อมูลเพิ่มเติมเกี่ยวกับการติดตั้งใช้งานฝั่งเซิร์ฟเวอร์ได้ที่สร้างการท้าทายและสร้างตัวเลือกคำขอข้อมูลเข้าสู่ระบบ
ตัวเลือกจะมีลักษณะคล้ายกับตัวเลือกต่อไปนี้
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับช่องต่างๆ ได้ในบล็อกโพสต์เกี่ยวกับการลงชื่อเข้าใช้ด้วย พาสคีย์
สร้างออบเจ็กต์ที่จำเป็นในการรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ
ในแอป ให้ใช้ตัวเลือกเพื่อสร้างออบเจ็กต์ GetPublicKeyCredentialOption
ในตัวอย่างต่อไปนี้ requestJson แสดงถึงตัวเลือกที่เซิร์ฟเวอร์ส่งมา
// Get password logins from the credential provider on the user's device.
val getPasswordOption = GetPasswordOption()
// Get passkeys from the credential provider on the user's device.
val getPublicKeyCredentialOption = GetPublicKeyCredentialOption(
requestJson = requestJson
)
จากนั้นห่อ GetPublicKeyCredentialOption ในออบเจ็กต์ GetCredentialRequest
val credentialRequest = GetCredentialRequest(
// Include all the sign-in options that your app supports.
listOf(getPasswordOption, getPublicKeyCredentialOption),
// Defines whether you prefer to use only immediately available
// credentials or hybrid credentials.
preferImmediatelyAvailableCredentials = preferImmediatelyAvailableCredentials
)
ไม่บังคับ: ลดเวลาในการตอบสนองการลงชื่อเข้าใช้
ใน Android 14 ขึ้นไป คุณสามารถลดเวลาในการตอบสนองเมื่อแสดงตัวเลือกบัญชี
ได้โดยใช้วิธี prepareGetCredential() ก่อนที่จะเรียกใช้
getCredential()
วิธี prepareGetCredential() จะแสดงผลออบเจ็กต์
PrepareGetCredentialResponse ซึ่งจะถูกแคชไว้ ซึ่งจะช่วยให้วิธี getCredential() ในขั้นตอนถัดไปแสดงตัวเลือกบัญชีพร้อมข้อมูลที่แคชไว้
coroutineScope {
val response = credentialManager.prepareGetCredential(
GetCredentialRequest(
listOf(
// Include all the sign-in options that your app supports
getPublicKeyCredentialOption,
getPasswordOption
)
)
)
}
เปิดใช้ขั้นตอนการลงชื่อเข้าใช้
เรียกใช้วิธี getCredential() เพื่อแสดงตัวเลือกบัญชีแก่ผู้ใช้ ใช้ข้อมูลโค้ดต่อไปนี้เป็นข้อมูลอ้างอิงสำหรับวิธีเปิดใช้ขั้นตอนการลงชื่อเข้าใช้
// Use an activity-based context to avoid undefined system UI
// launching behavior.
val context = MutableContextWrapper(activityContext)
coroutineScope {
try {
result = credentialManager.getCredential(
// Use MutableContextWrapper to avoid memory leak during configuration changes
context = context,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
จัดการการตอบกลับ
จัดการการตอบกลับซึ่งอาจมีออบเจ็กต์ข้อมูลเข้าสู่ระบบประเภทต่างๆ
fun handleSignIn(result: GetCredentialResponse) {
// Handle the successfully returned credential.
val credential = result.credential
when (credential) {
is PublicKeyCredential -> {
val responseJson = credential.authenticationResponseJson
// Share responseJson i.e. a GetCredentialResponse on your server to
// validate and authenticate
}
is PasswordCredential -> {
val username = credential.id
val password = credential.password
// Use id and password to send to your server to validate
// and authenticate
}
is CustomCredential -> {
// If you are also using any external sign-in libraries, parse them
// here with the utility functions provided.
if (credential.type == ExampleCustomCredential.TYPE) {
try {
val ExampleCustomCredential =
ExampleCustomCredential.createFrom(credential.data)
// Extract the required credentials and complete the authentication as per
// the federated sign in or any external sign in library flow
} catch (e: ExampleCustomCredential.ExampleCustomCredentialParsingException) {
// Unlikely to happen. If it does, you likely need to update the dependency
// version of your external sign-in library.
Log.e(TAG, "Failed to parse an ExampleCustomCredential", e)
}
} else {
// Catch any unrecognized custom credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential")
}
}
}
PublicKeyCredential ที่แสดงผลจากการตรวจสอบสิทธิ์โดยพื้นฐานแล้วคือการยืนยันที่ลงนามแล้ว ซึ่งมีโครงสร้างดังนี้
{
"id": "<credential ID>",
"type": "public-key",
"rawId": "<raw credential ID>",
"response": {
"clientDataJSON": "<signed client data containing challenge>",
"authenticatorData": "<authenticator metadata>",
"signature": "<digital signature to be verified>",
"userHandle": "<user ID from credential registration>"
}
}
คุณต้องยืนยันข้อมูลเข้าสู่ระบบในเซิร์ฟเวอร์ ดูข้อมูลเพิ่มเติมได้ที่ยืนยันและ ลงชื่อเข้าใช้ผู้ใช้
จัดการข้อยกเว้น
คุณควรจัดการข้อยกเว้นคลาสย่อยทั้งหมดของ GetCredentialException
ดูวิธีจัดการข้อยกเว้นแต่ละรายการได้ในคู่มือการแก้ปัญหา
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}