Tích hợp tính năng tạo và đăng nhập bằng khoá truy cập bằng một lần chạm với lời nhắc sinh trắc học

Trên Android 15, Trình quản lý thông tin xác thực hỗ trợ quy trình một lần nhấn để tạo và truy xuất thông tin xác thực. Trong quy trình này, thông tin về thông tin xác thực đang được tạo hoặc đang được sử dụng sẽ hiển thị trực tiếp trong Lời nhắc sinh trắc học, cùng với một điểm truy cập vào các lựa chọn khác. Quy trình đơn giản hoá này tạo ra một quy trình tạo và truy xuất thông tin xác thực hiệu quả và hợp lý hơn.

Yêu cầu:

  • Hệ thống nhận dạng sinh trắc học đã được thiết lập trên thiết bị của người dùng và người dùng cho phép sử dụng hệ thống này để xác thực vào các ứng dụng.
  • Đối với quy trình đăng nhập, tính năng này chỉ được bật cho các trường hợp một tài khoản, ngay cả khi có nhiều thông tin xác thực (chẳng hạn như khoá truy cập và mật khẩu) cho tài khoản đó.

Bật tính năng một lần nhấn trên quy trình tạo khoá truy cập

Các bước tạo của phương thức này khớp với quy trình tạo thông tin xác thực hiện có. Trong BeginCreatePublicKeyCredentialRequest, hãy sử dụng handleCreatePasskeyQuery() để xử lý yêu cầu nếu yêu cầu đó dành cho khoá truy cập.

is BeginCreatePublicKeyCredentialRequest -> {
    Log.i(TAG, "Request is passkey type")
    return handleCreatePasskeyQuery(request, passwordCount, passkeyCount)
}

Trong handleCreatePasskeyQuery(), hãy đưa BiometricPromptData vào lớp CreateEntry:

val createEntry = CreateEntry(
    // Additional properties...
    biometricPromptData = BiometricPromptData(
        allowedAuthenticators = allowedAuthenticator
    ),
)

Trình cung cấp thông tin xác thực phải đặt rõ ràng thuộc tính allowedAuthenticator trong thực thể BiometricPromptData. Nếu không đặt thuộc tính này, giá trị sẽ mặc định là DEVICE_WEAK. Đặt thuộc tính cryptoObject không bắt buộc nếu cần cho trường hợp sử dụng của bạn.

Bật tính năng một lần nhấn trên quy trình khoá truy cập đăng nhập

Tương tự như quy trình tạo khoá truy cập, quy trình này sẽ tuân theo quy trình thiết lập hiện có để xử lý việc đăng nhập của người dùng. Trong BeginGetPublicKeyCredentialOption, hãy sử dụng populatePasskeyData() để thu thập thông tin liên quan về yêu cầu xác thực:

is BeginGetPublicKeyCredentialOption -> {
    // ... other logic

    populatePasskeyData(
        origin,
        option,
        responseBuilder,
        autoSelectEnabled,
        allowedAuthenticator
    )

    // ... other logic as needed
}

Tương tự như CreateEntry, một thực thể BiometricPromptData được đặt thành thực thể PublicKeyCredentialEntry. Nếu không được đặt rõ ràng, allowedAuthenticator sẽ mặc định là BIOMETRIC_WEAK.

PublicKeyCredentialEntry(
    // other properties...

    biometricPromptData = BiometricPromptData(
        allowedAuthenticators = allowedAuthenticator
    )
)

Xử lý lựa chọn mục nhập thông tin xác thực

Trong khi xử lý lựa chọn mục nhập thông tin xác thực để tạo khoá truy cập hoặc lựa chọn khoá truy cập trong khi đăng nhập, hãy gọi PendingIntentHandler's retrieveProviderCreateCredentialRequest hoặc retrieveProviderGetCredentialRequest (tuỳ theo trường hợp). Các đối tượng này trả về chứa siêu dữ liệu cần thiết cho trình cung cấp. Ví dụ: khi xử lý lựa chọn mục nhập tạo khoá truy cập, hãy cập nhật đoạn mã như sau:

val createRequest = PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
if (createRequest == null) {
    Log.i(TAG, "request is null")
    setUpFailureResponseAndFinish("Unable to extract request from intent")
    return
}
// Other logic...

val biometricPromptResult = createRequest.biometricPromptResult

// Add your logic based on what needs to be done
// after getting biometrics

if (createRequest.callingRequest is CreatePublicKeyCredentialRequest) {
    val publicKeyRequest: CreatePublicKeyCredentialRequest =
        createRequest.callingRequest as CreatePublicKeyCredentialRequest

    if (biometricPromptResult == null) {
        // Do your own authentication flow, if needed
    } else if (biometricPromptResult.isSuccessful) {
        createPasskey(
            publicKeyRequest.requestJson,
            createRequest.callingAppInfo,
            publicKeyRequest.clientDataHash,
            accountId
        )
    } else {
        val error = biometricPromptResult.authenticationError
        // Process the error
    }

    // Other logic...
}

Ví dụ này chứa thông tin về việc quy trình sinh trắc học thành công. Ví dụ này cũng chứa thông tin khác về thông tin xác thực. Nếu quy trình không thành công, hãy sử dụng mã lỗi trong biometricPromptResult.authenticationError để đưa ra quyết định. Các mã lỗi được trả về trong biometricPromptResult.authenticationError.errorCode là các mã lỗi giống nhau được xác định trong thư viện androidx.biometric, chẳng hạn như androidx.biometric.BiometricPrompt.NO_SPACE, androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS, androidx.biometric.BiometricPrompt.ERROR_TIMEOUT và các mã lỗi tương tự. authenticationError cũng sẽ chứa một thông báo lỗi được liên kết với errorCode có thể hiển thị trên giao diện người dùng.

Tương tự, hãy trích xuất siêu dữ liệu trong retrieveProviderGetCredentialRequest. Kiểm tra xem quy trình sinh trắc học của bạn có phải là null hay không. Nếu có, hãy định cấu hình hệ thống nhận dạng sinh trắc học của riêng bạn để xác thực. Điều này tương tự như cách hoạt động của thao tác get:

val getRequest =
    PendingIntentHandler.retrieveProviderGetCredentialRequest(intent)

if (getRequest == null) {
    Log.i(TAG, "request is null")
    setUpFailureResponseAndFinish("Unable to extract request from intent")
    return
}

// Other logic...

val biometricPromptResult = getRequest.biometricPromptResult

// Add your logic based on what needs to be done
// after getting biometrics

if (biometricPromptResult == null) {
    // Do your own authentication flow, if necessary
} else if (biometricPromptResult.isSuccessful) {

    Log.i(TAG, "The response from the biometricPromptResult was ${biometricPromptResult.authenticationResult?.authenticationType}")

    validatePasskey(
        publicKeyRequest.requestJson,
        origin,
        packageName,
        uid,
        passkey.username,
        credId,
        privateKey
    )
} else {
    val error = biometricPromptResult.authenticationError
    // Process the error
}

// Other logic...