การรองรับพาสคีย์ การลงชื่อเข้าใช้แบบรวมศูนย์ และผู้ให้บริการตรวจสอบสิทธิ์บุคคลที่สาม ทำให้ Credential Manager เป็น API ที่แนะนำสำหรับการตรวจสอบสิทธิ์ใน Android ซึ่งมีสภาพแวดล้อมที่ปลอดภัยและสะดวกสบายที่ ช่วยให้ผู้ใช้ซิงค์และจัดการข้อมูลเข้าสู่ระบบได้ สําหรับนักพัฒนาแอปที่ใช้ข้อมูลเข้าสู่ระบบ FIDO2 ในเครื่อง คุณควรอัปเดตแอปให้รองรับการตรวจสอบสิทธิ์ด้วยพาสคีย์โดยผสานรวมกับ Credential Manager API เอกสารนี้ อธิบายวิธีย้ายข้อมูลโปรเจ็กต์จาก FIDO2 ไปยัง Credential Manager
เหตุผลที่ควรย้ายข้อมูลจาก FIDO2 ไปยังเครื่องมือจัดการข้อมูลเข้าสู่ระบบ
ในกรณีส่วนใหญ่ คุณควรย้ายข้อมูลผู้ให้บริการตรวจสอบสิทธิ์ของแอป Android ไปยัง Credential Manager เหตุผลที่ควรย้ายข้อมูลไปยังเครื่องมือจัดการข้อมูลเข้าสู่ระบบมีดังนี้
- การรองรับพาสคีย์: เครื่องมือจัดการข้อมูลเข้าสู่ระบบรองรับพาสคีย์ ซึ่งเป็นกลไกการตรวจสอบสิทธิ์แบบใหม่ที่ไม่ต้องใช้รหัสผ่าน ที่ปลอดภัยและใช้งานง่ายกว่ารหัสผ่าน
- วิธีการลงชื่อเข้าใช้หลายวิธี: เครื่องมือจัดการข้อมูลเข้าสู่ระบบรองรับวิธีการลงชื่อเข้าใช้หลายวิธี ซึ่งรวมถึงรหัสผ่าน พาสคีย์ และวิธีการลงชื่อเข้าใช้แบบรวม ซึ่งจะช่วยให้ผู้ใช้ตรวจสอบสิทธิ์แอปของคุณได้ง่ายขึ้น ไม่ว่าผู้ใช้จะชอบวิธีการตรวจสอบสิทธิ์ใดก็ตาม
- การรองรับผู้ให้บริการข้อมูลเข้าสู่ระบบของบุคคลที่สาม: ใน Android 14 ขึ้นไป เครื่องมือจัดการข้อมูลเข้าสู่ระบบรองรับผู้ให้บริการข้อมูลเข้าสู่ระบบของบุคคลที่สามหลายราย ซึ่งหมายความว่าผู้ใช้จะใช้ข้อมูลเข้าสู่ระบบที่มีอยู่จากผู้ให้บริการรายอื่นเพื่อลงชื่อเข้าใช้แอปของคุณได้
- ประสบการณ์ของผู้ใช้ที่สอดคล้องกัน: เครื่องมือจัดการข้อมูลเข้าสู่ระบบมอบประสบการณ์ของผู้ใช้ที่สอดคล้องกันมากขึ้นสำหรับการตรวจสอบสิทธิ์ในแอปและกลไกการลงชื่อเข้าใช้ ซึ่งจะช่วยให้ผู้ใช้เข้าใจและใช้ขั้นตอนการตรวจสอบสิทธิ์ของแอปได้ง่ายขึ้น
หากต้องการเริ่มย้ายข้อมูลจาก FIDO2 ไปยังเครื่องมือจัดการข้อมูลเข้าสู่ระบบ ให้ทำตามขั้นตอนด้านล่าง
อัปเดตทรัพยากร Dependency
อัปเดตปลั๊กอิน Kotlin ใน build.gradle ของโปรเจ็กต์เป็นเวอร์ชัน 1.8.10 ขึ้นไป
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
ใน
build.gradle
ของโปรเจ็กต์ ให้อัปเดตทรัพยากร Dependency เพื่อใช้ เวอร์ชันล่าสุดของ Credential Manager และไลบรารีการตรวจสอบสิทธิ์ของ Play Servicesdependencies { // ... // Credential Manager: implementation 'androidx.credentials:credentials:<latest-version>' // Play Services Authentication: // Optional - needed for credentials support from play services, for devices running // Android 13 and below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
แทนที่การเริ่มต้น FIDO ด้วยการเริ่มต้น Credential Manager เพิ่มการประกาศนี้ ในคลาสที่คุณใช้สำหรับวิธีการสร้างและลงชื่อเข้าใช้ด้วยพาสคีย์
val credMan = CredentialManager.create(context)
สร้างพาสคีย์
คุณจะต้องสร้างพาสคีย์ใหม่ เชื่อมโยงกับบัญชีของผู้ใช้ และ จัดเก็บคีย์สาธารณะของพาสคีย์ไว้ในเซิร์ฟเวอร์ก่อนที่ผู้ใช้จะลงชื่อเข้าใช้ด้วยพาสคีย์ได้ ตั้งค่าแอปให้มีความสามารถนี้โดยอัปเดตการเรียกฟังก์ชัน register
หากต้องการรับพารามิเตอร์ที่จำเป็นซึ่งส่งไปยังเมธอด
createCredential()
ระหว่างการสร้างพาสคีย์ ให้เพิ่มname("residentKey").value("required")
ตามที่อธิบายไว้ในข้อกำหนด WebAuthn) ลงในการเรียกเซิร์ฟเวอร์registerRequest()
suspend fun registerRequest() { // ... val call = client.newCall( Builder() .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() ) // ... }
ตั้งค่า
return
ประเภทสำหรับregisterRequest()
และฟังก์ชันย่อยทั้งหมดเป็นJSONObject
suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Builder() .url("$BASE_URL/<your api url>") .addHeader("Cookie", formatCookie(sessionId)) .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("authenticatorAttachment").value("platform") name("userVerification").value("required") name("residentKey").value("required") } }).build() ) val response = call.await() return response.result("Error calling the api") { parsePublicKeyCredentialCreationOptions( body ?: throw ApiException("Empty response from the api call") ) } }
นำวิธีการที่จัดการการเรียกใช้ Intent และผลลัพธ์ของกิจกรรมออกจากมุมมองอย่างปลอดภัย
เนื่องจากตอนนี้
registerRequest()
จะแสดงผลเป็นJSONObject
คุณจึงไม่จำเป็นต้อง สร้างPendingIntent
แทนที่ Intent ที่ส่งคืนด้วยJSONObject
อัปเดตการเรียกตัวเรียกใช้ Intent เพื่อเรียกcreateCredential()
จาก Credential Manager API เรียกใช้เมธอดcreateCredential()
APIsuspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request = request as CreateCredentialRequest, context = activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
เมื่อโทรสำเร็จแล้ว ให้ส่งการตอบกลับไปยังเซิร์ฟเวอร์ คำขอและการตอบกลับสำหรับการเรียกนี้จะคล้ายกับการติดตั้งใช้งาน FIDO2 จึงไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ
ตรวจสอบสิทธิ์ด้วยพาสคีย์
หลังจากตั้งค่าการสร้างพาสคีย์แล้ว คุณสามารถตั้งค่าแอปเพื่อให้ผู้ใช้ ลงชื่อเข้าใช้และตรวจสอบสิทธิ์โดยใช้พาสคีย์ได้ โดยคุณจะต้องอัปเดต รหัสการตรวจสอบสิทธิ์เพื่อจัดการผลลัพธ์ของเครื่องมือจัดการข้อมูลเข้าสู่ระบบ และใช้ ฟังก์ชันเพื่อตรวจสอบสิทธิ์ผ่านพาสคีย์
- การเรียกคำขอลงชื่อเข้าใช้ไปยังเซิร์ฟเวอร์เพื่อรับข้อมูลที่จำเป็นในการส่งไปยังคำขอ
getCredential()
จะเหมือนกับการติดตั้งใช้งาน FIDO2 ไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ การเรียกคำขอลงทะเบียนจะคล้ายกับการเรียกคำขอลงทะเบียน โดยการตอบกลับที่ส่งคืนจะอยู่ในรูปแบบ JSONObject
/** * @param sessionId The session ID to be used for the sign-in. * @param credentialId The credential ID of this device. * @return a JSON object. */ suspend fun signinRequest(): ApiResult<JSONObject> { val call = client.newCall(Builder().url(buildString { append("$BASE_URL/signinRequest") }).method("POST", jsonRequestBody {}) .build() ) val response = call.await() return response.result("Error calling /signinRequest") { parsePublicKeyCredentialRequestOptions( body ?: throw ApiException("Empty response from /signinRequest") ) } } /** * @param sessionId The session ID to be used for the sign-in. * @param response The JSONObject for signInResponse. * @param credentialId id/rawId. * @return A list of all the credentials registered on the server, * including the newly-registered one. */ suspend fun signinResponse( sessionId: String, response: JSONObject, credentialId: String ): ApiResult<Unit> { val call = client.newCall( Builder().url("$BASE_URL/signinResponse") .addHeader("Cookie",formatCookie(sessionId)) .method("POST", jsonRequestBody { name("id").value(credentialId) name("type").value(PUBLIC_KEY.toString()) name("rawId").value(credentialId) name("response").objectValue { name("clientDataJSON").value( response.getString("clientDataJSON") ) name("authenticatorData").value( response.getString("authenticatorData") ) name("signature").value( response.getString("signature") ) name("userHandle").value( response.getString("userHandle") ) } }).build() ) val apiResponse = call.await() return apiResponse.result("Error calling /signingResponse") { } }
นำวิธีการที่จัดการการเรียกใช้ Intent และการเรียกผลลัพธ์ของกิจกรรมออกจากมุมมองอย่างปลอดภัย
เนื่องจากตอนนี้
signInRequest()
จะแสดงผลJSONObject
คุณจึงไม่จำเป็นต้องสร้างPendingIntent
แทนที่ Intent ที่แสดงผลด้วยJSONObject
แล้วเรียกใช้getCredential()
จากเมธอด APIsuspend fun getPasskey( activity: Activity, creationResult: JSONObject ): GetCredentialResponse? { Toast.makeText( activity, "Fetching previously stored credentials", Toast.LENGTH_SHORT) .show() var result: GetCredentialResponse? = null try { val request= GetCredentialRequest( listOf( GetPublicKeyCredentialOption( creationResult.toString(), null ), GetPasswordOption() ) ) result = credMan.getCredential(activity, request) if (result.credential is PublicKeyCredential) { val publicKeycredential = result.credential as PublicKeyCredential Log.i("TAG", "Passkey ${publicKeycredential.authenticationResponseJson}") return result } } catch (e: Exception) { showErrorAlert(activity, e) } return result }
เมื่อการเรียกสำเร็จแล้ว ให้ส่งการตอบกลับไปยังเซิร์ฟเวอร์เพื่อ ตรวจสอบและยืนยันตัวตนผู้ใช้ พารามิเตอร์คำขอและการตอบกลับสำหรับการเรียก API นี้คล้ายกับการติดตั้งใช้งาน FIDO2 จึงไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ
แหล่งข้อมูลเพิ่มเติม
- ข้อมูลอ้างอิงตัวอย่างของ Credential Manager
- Codelab ของ Credential Manager
- นำการตรวจสอบสิทธิ์ที่ราบรื่นมาสู่แอปของคุณด้วยพาสคีย์โดยใช้ Credential Manager API
- Codelab ของ FIDO2