คู่มือนี้จะอธิบายต่อเกี่ยวกับการติดตั้งใช้งานการใช้พาสคีย์เพื่อการตรวจสอบสิทธิ์ ก่อนที่ผู้ใช้จะลงชื่อเข้าใช้ด้วยพาสคีย์ได้ คุณต้องทำตาม วิธีการในสร้างพาสคีย์ให้เสร็จสมบูรณ์ด้วย
หากต้องการตรวจสอบสิทธิ์ด้วยพาสคีย์ คุณต้องเรียกข้อมูลตัวเลือกที่จำเป็นเพื่อ เรียกคีย์สาธารณะจากเซิร์ฟเวอร์แอปก่อน แล้วเรียกใช้ Credential Manager API เพื่อเรียกคีย์สาธารณะ จากนั้นจัดการการตอบกลับการลงชื่อเข้าใช้ อย่างเหมาะสม
ภาพรวม
คู่มือนี้มุ่งเน้นที่การเปลี่ยนแปลงที่จำเป็นในแอปไคลเอ็นต์เพื่อลงชื่อเข้าใช้ ผู้ใช้ด้วยพาสคีย์ และให้ภาพรวมโดยย่อของการติดตั้งใช้งานฝั่งเซิร์ฟเวอร์ของแอป ดูข้อมูลเพิ่มเติมเกี่ยวกับการผสานรวมฝั่งเซิร์ฟเวอร์ได้ที่การตรวจสอบสิทธิ์ด้วยพาสคีย์ฝั่งเซิร์ฟเวอร์
หากต้องการดึงตัวเลือกพาสคีย์และรหัสผ่านทั้งหมดที่เชื่อมโยงกับบัญชีของผู้ใช้ ให้ทำตามขั้นตอนต่อไปนี้
- รับตัวเลือกคำขอข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์: ส่งคำขอจากแอปไปยังเซิร์ฟเวอร์การตรวจสอบสิทธิ์เพื่อเริ่มกระบวนการลงชื่อเข้าใช้ด้วยพาสคีย์ จากเซิร์ฟเวอร์ ให้ส่งตัวเลือกที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ รวมถึงการท้าทายที่ไม่ซ้ำกัน
- สร้างออบเจ็กต์ที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ: ห่อหุ้ม
ตัวเลือกที่เซิร์ฟเวอร์ส่งมาในออบเจ็กต์
GetPublicKeyCredentialOption - (ไม่บังคับ) เตรียม getCredential: ใน Android 14 ขึ้นไป คุณสามารถ
ลดเวลาในการตอบสนองโดยแสดงตัวเลือกบัญชีโดยใช้เมธอด
prepareGetCredential()ก่อนเรียกใช้getCredential() - เปิดโฟลว์การลงชื่อเข้าใช้: เรียกใช้เมธอด
getCredential()เพื่อลงชื่อเข้าใช้ ผู้ใช้ - จัดการการตอบกลับ: จัดการการตอบกลับที่เป็นไปได้แต่ละรายการของข้อมูลเข้าสู่ระบบ
- จัดการข้อยกเว้น: ตรวจสอบว่าคุณจัดการข้อยกเว้น อย่างเหมาะสม
1. รับตัวเลือกคำขอข้อมูลเข้าสู่ระบบจากเซิร์ฟเวอร์
ขอตัวเลือกที่จำเป็นต่อการรับข้อมูลเข้าสู่ระบบคีย์สาธารณะจากเซิร์ฟเวอร์
รวมถึง challenge ซึ่งไม่ซ้ำกันสำหรับการพยายามลงชื่อเข้าใช้แต่ละครั้ง ดูข้อมูลเพิ่มเติมเกี่ยวกับการติดตั้งใช้งานฝั่งเซิร์ฟเวอร์ได้ที่สร้าง
ชาเลนจ์และสร้างตัวเลือกคำขอข้อมูลเข้าสู่ระบบ
ตัวเลือกจะมีลักษณะคล้ายกับตัวเลือกต่อไปนี้
{
"challenge": "<your app challenge>",
"allowCredentials": [],
"rpId": "<your app server domain>"
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับช่องได้ในบล็อกโพสต์เรื่องการลงชื่อเข้าใช้ด้วย พาสคีย์
2. สร้างออบเจ็กต์ที่จำเป็นเพื่อรับข้อมูลเข้าสู่ระบบคีย์สาธารณะ
ในแอป ให้ใช้ตัวเลือกเพื่อสร้างออบเจ็กต์ 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
)
3. ไม่บังคับ: ลดเวลาในการตอบสนองของการลงชื่อเข้าใช้
ใน 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
)
)
)
}
4. เปิดโฟลว์การลงชื่อเข้าใช้
เรียกใช้เมธอด getCredential() เพื่อแสดงตัวเลือกบัญชีแก่ผู้ใช้ ใช้ข้อมูลโค้ดต่อไปนี้เป็นข้อมูลอ้างอิงสำหรับวิธีเปิดโฟลว์การลงชื่อเข้าใช้
coroutineScope {
try {
result = credentialManager.getCredential(
// Use an activity-based context to avoid undefined system UI
// launching behavior.
context = activityContext,
request = credentialRequest
)
handleSignIn(result)
} catch (e: GetCredentialException) {
// Handle failure
}
}
5. จัดการคำตอบ
จัดการการตอบกลับ ซึ่งอาจมีออบเจ็กต์ข้อมูลเข้าสู่ระบบประเภทต่างๆ อย่างใดอย่างหนึ่ง
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>"
}
}
คุณต้องยืนยันข้อมูลเข้าสู่ระบบในเซิร์ฟเวอร์ ดูข้อมูลเพิ่มเติมได้ที่ยืนยันและ ลงชื่อเข้าใช้ผู้ใช้
6. จัดการข้อยกเว้น
คุณควรจัดการข้อยกเว้นของคลาสย่อยทั้งหมดของ GetCredentialException
ดูวิธีจัดการข้อยกเว้นแต่ละรายการได้ในคู่มือการแก้ปัญหา
coroutineScope {
try {
result = credentialManager.getCredential(
context = activityContext,
request = credentialRequest
)
} catch (e: GetCredentialException) {
Log.e("CredentialManager", "No credential available", e)
}
}