Credential Manager เป็น API ที่แนะนำสำหรับการตรวจสอบสิทธิ์ใน Android ซึ่งรองรับพาสคีย์, การลงชื่อเข้าใช้แบบรวมศูนย์ และผู้ให้บริการตรวจสอบสิทธิ์บุคคลที่สาม โดยมีสภาพแวดล้อมที่ปลอดภัยและสะดวกสบายซึ่งช่วยให้ผู้ใช้ซิงค์และจัดการข้อมูลเข้าสู่ระบบได้ สำหรับนักพัฒนาแอปที่ใช้ข้อมูลเข้าสู่ระบบ FIDO2 ในเครื่อง คุณควรอัปเดตแอปให้รองรับการตรวจสอบสิทธิ์ด้วยพาสคีย์โดยผสานรวมกับ Credential Manager API เอกสารนี้อธิบายวิธีย้ายข้อมูลโปรเจ็กต์จาก FIDO2 ไปยัง Credential Manager
เหตุผลที่ควรย้ายข้อมูลจาก FIDO2 ไปยัง Credential Manager
ในกรณีส่วนใหญ่ คุณควรย้ายข้อมูลผู้ให้บริการตรวจสอบสิทธิ์ของแอป Android ไปยัง Credential Manager เหตุผลที่ควรย้ายข้อมูลไปยัง Credential Manager ได้แก่
- การรองรับพาสคีย์: Credential Manager รองรับพาสคีย์ ซึ่งเป็นกลไกการตรวจสอบสิทธิ์แบบใหม่ที่ไม่ต้องใช้รหัสผ่าน ซึ่งปลอดภัยและใช้งานง่ายกว่ารหัสผ่าน
- วิธีการลงชื่อเข้าใช้หลายวิธี: Credential Manager รองรับวิธีการลงชื่อเข้าใช้หลายวิธี ซึ่งรวมถึงรหัสผ่าน พาสคีย์ และวิธีการลงชื่อเข้าใช้แบบรวมศูนย์ ซึ่งจะช่วยให้ผู้ใช้ตรวจสอบสิทธิ์ในแอปได้ง่ายขึ้น ไม่ว่าจะใช้วิธีการตรวจสอบสิทธิ์ที่ต้องการแบบใดก็ตาม
- การรองรับผู้ให้บริการข้อมูลเข้าสู่ระบบของบุคคลที่สาม: ใน Android 14 ขึ้นไป Credential Manager รองรับผู้ให้บริการข้อมูลเข้าสู่ระบบของบุคคลที่สามหลายราย ซึ่งหมายความว่าผู้ใช้สามารถใช้ข้อมูลเข้าสู่ระบบที่มีอยู่จากผู้ให้บริการรายอื่นเพื่อลงชื่อเข้าใช้แอปของคุณได้
- ประสบการณ์ของผู้ใช้ที่สอดคล้องกัน: Credential Manager มอบประสบการณ์ของผู้ใช้ที่สอดคล้องกันมากขึ้นสำหรับการตรวจสอบสิทธิ์ในแอปและกลไกการลงชื่อเข้าใช้ต่างๆ ซึ่งจะช่วยให้ผู้ใช้เข้าใจและใช้ขั้นตอนการตรวจสอบสิทธิ์ของแอปได้ง่ายขึ้น
หากต้องการเริ่มการย้ายข้อมูลจาก FIDO2 ไปยัง Credential Manager ให้ทำตามขั้นตอนต่อไปนี้
อัปเดตทรัพยากร Dependency
อัปเดตปลั๊กอิน Kotlin ใน build.gradle ของโปรเจ็กต์เป็นเวอร์ชัน 1.8.10 ขึ้นไป
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }ใน
build.gradleของโปรเจ็กต์ ให้อัปเดตทรัพยากร Dependency เพื่อใช้ไลบรารี Credential Manager และบริการ Google Play Authentication เวอร์ชันล่าสุดdependencies { // ... // 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 lower: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }แทนที่การเริ่มต้น FIDO ด้วยการเริ่มต้น Credential Manager เพิ่มการประกาศนี้ในคลาสที่คุณใช้สำหรับวิธีการสร้างพาสคีย์และการลงชื่อเข้าใช้
val credMan = CredentialManager.create(context)
สร้างพาสคีย์
คุณจะต้องสร้างพาสคีย์ใหม่ เชื่อมโยงกับบัญชีของผู้ใช้ และจัดเก็บคีย์สาธารณะของพาสคีย์ไว้ในเซิร์ฟเวอร์ก่อนที่ผู้ใช้จะลงชื่อเข้าใช้ด้วยพาสคีย์ดังกล่าวได้ ตั้งค่าแอปให้มีความสามารถนี้โดยอัปเดตการเรียกใช้ฟังก์ชันการลงทะเบียน
หากต้องการรับพารามิเตอร์ที่จำเป็นซึ่งส่งไปยังเมธอด
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()และฟังก์ชันย่อยทั้งหมดเป็นJSONObjectsuspend 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 Launcher และผลลัพธ์ของกิจกรรมออกจากมุมมองของคุณอย่างปลอดภัย
เนื่องจากตอนนี้
registerRequest()แสดงผลเป็นJSONObjectคุณจึงไม่จำเป็นต้องสร้างPendingIntentแทนที่ Intent ที่แสดงผลด้วยJSONObjectอัปเดตการเรียกใช้ Intent Launcher เพื่อเรียกใช้createCredential()จาก Credential Manager API เรียกใช้เมธอด APIcreateCredential()suspend 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 จึงไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ
ตรวจสอบสิทธิ์ด้วยพาสคีย์
หลังจากตั้งค่าการสร้างพาสคีย์แล้ว คุณสามารถตั้งค่าแอปเพื่ออนุญาตให้ผู้ใช้ลงชื่อเข้าใช้และตรวจสอบสิทธิ์โดยใช้พาสคีย์ได้ โดยคุณจะต้องอัปเดตโค้ดการตรวจสอบสิทธิ์เพื่อจัดการผลลัพธ์ของ Credential Manager และใช้ฟังก์ชันเพื่อตรวจสอบสิทธิ์ผ่านพาสคีย์
- การเรียกคำขอลงชื่อเข้าใช้ไปยังเซิร์ฟเวอร์เพื่อรับข้อมูลที่จำเป็นซึ่งจะส่งไปยังคำขอ
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 Launcher และการเรียกใช้ผลลัพธ์ของกิจกรรมออกจากมุมมองของคุณอย่างปลอดภัย
เนื่องจากตอนนี้
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