Với khả năng hỗ trợ khoá truy cập, dịch vụ đăng nhập liên kết và trình cung cấp xác thực bên thứ ba, Trình quản lý thông tin xác thực là API được đề xuất cho hoạt động xác thực trên Android, giúp mang đến một môi trường an toàn, thuận tiện để người dùng có thể đồng bộ hoá và quản lý thông tin xác thực của họ. Đối với các nhà phát triển sử dụng thông tin xác thực FIDO2 trên máy, bạn nên cập nhật ứng dụng của mình để hỗ trợ hình thức xác thực bằng khoá truy cập thông qua việc tích hợp với API Trình quản lý thông tin xác thực. Tài liệu này mô tả cách di chuyển dự án của bạn từ FIDO2 sang Trình quản lý thông tin xác thực.
Lý do bạn nên chuyển từ FIDO2 sang Trình quản lý thông tin xác thực
Trong hầu hết các trường hợp, bạn nên di chuyển từ trình cung cấp dịch vụ xác thực của ứng dụng Android sang Trình quản lý thông tin xác thực: Sau đây là những lý do bạn nên di chuyển sang Trình quản lý thông tin xác thực:
- Hỗ trợ khoá truy cập: Trình quản lý thông tin xác thực hỗ trợ khoá truy cập. Đây là một cơ chế xác thực mới, không cần mật khẩu, an toàn và dễ sử dụng hơn so với mật khẩu.
- Nhiều phương thức đăng nhập: Trình quản lý thông tin xác thực hỗ trợ nhiều phương thức đăng nhập, trong đó có mật khẩu, khoá truy cập và phương thức đăng nhập liên kết. Điều này giúp người dùng xác thực với ứng dụng của bạn dễ dàng hơn, bất kể phương thức xác thực họ ưu tiên là gì.
- Hỗ trợ trình cung cấp thông tin xác thực bên thứ ba: Trên Android 14 trở lên, Trình quản lý thông tin xác thực hỗ trợ nhiều trình cung cấp thông tin xác thực bên thứ ba. Điều này có nghĩa là người dùng có thể sử dụng thông tin xác thực hiện có của họ từ các trình cung cấp khác để đăng nhập vào ứng dụng của bạn.
- Trải nghiệm người dùng nhất quán: Trình quản lý thông tin xác thực mang đến một trải nghiệm nhất quán hơn cho người dùng khi xác thực trên các ứng dụng và cơ chế đăng nhập. Điều này giúp người dùng hiểu và sử dụng quy trình xác thực của ứng dụng dễ dàng hơn.
Để bắt đầu quá trình di chuyển từ FIDO2 sang Trình quản lý thông tin xác thực, hãy làm theo các bước dưới đây.
Cập nhật phần phụ thuộc
Cập nhật trình bổ trợ Kotlin trong build.gradle của dự án lên phiên bản 1.8.10 trở lên.
plugins { //… id 'org.jetbrains.kotlin.android' version '1.8.10' apply false //… }
Trong build.gradle của dự án, hãy cập nhật các phần phụ thuộc để sử dụng Trình quản lý thông tin xác thực và tính năng Xác thực Dịch vụ Play.
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 below: implementation 'androidx.credentials:credentials-play-services-auth:<latest-version>' // ... }
Thay thế quy trình khởi động FIDO bằng quy trình khởi động Trình quản lý thông tin xác thực. Thêm phần khai báo này vào lớp mà bạn dùng để tạo khoá truy cập và phương thức đăng nhập:
val credMan = CredentialManager.create(context)
Tạo khoá truy cập
Bạn cần tạo một khoá truy cập mới, liên kết khoá đó với một tài khoản của người dùng và lưu trữ khoá công khai của khoá truy cập đó trên máy chủ của bạn, thì người dùng mới có thể đăng nhập bằng khoá truy cập đó. Thiết lập tính năng này cho ứng dụng của bạn bằng cách cập nhật các lệnh gọi hàm register.
Để lấy các tham số cần thiết đã được gửi đến phương thức
createCredential()
trong quá trình tạo khoá truy cập, hãy thêmname("residentKey").value("required")
như mô tả trong phần thông số kỹ thuật WebAuthn vào lệnh gọi máy chủregisterRequest()
.suspend fun registerRequest(sessionId: String ... { // ... .method("POST", jsonRequestBody { name("attestation").value("none") name("authenticatorSelection").objectValue { name("residentKey").value("required") } }).build() // ... }
Đặt kiểu
return
choregisterRequest()
và đặt tất cả các hàm con thànhJSONObject
.suspend fun registerRequest(sessionId: String): ApiResult<JSONObject> { val call = client.newCall( Request.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") ) } }
Yên tâm xoá mọi phương thức giúp xử lý lệnh gọi kết quả hoạt động và trình chạy ý định từ khung hiển thị của bạn.
Vì
registerRequest()
hiện trả về mộtJSONObject
, nên bạn không cần tạoPendingIntent
. Thay thế ý định được trả về bằngJSONObject
. Cập nhật các lệnh gọi của trình chạy ý định để gọicreateCredential()
từ API Trình quản lý thông tin xác thực. Gọi phương thức APIcreateCredential()
.suspend fun createPasskey( activity: Activity, requestResult: JSONObject ): CreatePublicKeyCredentialResponse? { val request = CreatePublicKeyCredentialRequest(requestResult.toString()) var response: CreatePublicKeyCredentialResponse? = null try { response = credMan.createCredential( request as CreateCredentialRequest, activity ) as CreatePublicKeyCredentialResponse } catch (e: CreateCredentialException) { showErrorAlert(activity, e) return null } return response }
Sau khi lệnh gọi có trạng thái thành công, hãy gửi lại phản hồi này cho máy chủ. Yêu cầu và phản hồi cho lệnh gọi này giống như khi bạn triển khai FIDO2, vì vậy, bạn không cần thay đổi gì.
Xác thực bằng khoá truy cập
Sau khi thiết lập tính năng tạo khoá truy cập, bạn có thể thiết lập ứng dụng của mình sao cho người dùng có thể đăng nhập và xác thực bằng khoá truy cập của họ. Để làm vậy, bạn sẽ cập nhật mã xác thực dùng để xử lý các kết quả của Trình quản lý thông tin xác thực và triển khai một hàm để xác thực thông qua khoá truy cập.
- Lệnh gọi yêu cầu đăng nhập của bạn đến máy chủ để lấy thông tin cần thiết được gửi tới yêu cầu
getCredential()
cũng giống như khi bạn triển khai FIDO2. Do đó, bạn không cần thay đổi gì. Tương tự như lệnh gọi yêu cầu đăng ký, phản hồi được trả về có định dạng 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") { } }
Yên tâm xoá mọi phương thức giúp xử lý lệnh gọi kết quả hoạt động và trình chạy ý định từ khung hiển thị của bạn.
Vì
signInRequest()
hiện trả về mộtJSONObject
, nên bạn không cần tạoPendingIntent
. Thay thế ý định được trả về bằngJSONObject
và gọigetCredential()
từ các phương thức API.suspend 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 }
Sau khi lệnh gọi có trạng thái thành công, hãy gửi lại phản hồi cho máy chủ để kiểm tra và xác thực người dùng. Các tham số cho yêu cầu và phản hồi của lệnh gọi API này cũng giống như khi bạn triển khai FIDO2, nên bạn không cần thay đổi gì.
Tài nguyên khác
- Tài liệu tham khảo mẫu cho Trình quản lý thông tin xác thực
- Lớp học lập trình về Trình quản lý thông tin xác thực
- Cung cấp phương thức xác thực liền mạch cho ứng dụng của bạn bằng khoá truy cập thông qua API Trình quản lý thông tin xác thực
- Lớp học lập trình FIDO2