整合「輕觸一下密碼金鑰建立流程」和生物特徵辨識提示登入功能

在 Android 15 中,Credential Manager 支援透過單次輕觸流程使用憑證 建立與擷取作業在這個流程中, 這些資訊會直接顯示在生物特徵辨識提示中 當中包含更多選項簡化作業流程 簡化憑證的建立與擷取程序。

需求條件:

  • 使用者的裝置已設定生物特徵辨識功能,且使用者允許 導入應用程式
  • 在登入流程中,這項功能僅適用於單一帳戶情況, 如果有多個可用的憑證 (例如密碼金鑰和密碼) 。

啟用密碼金鑰建立流程的輕觸一下

這個方法的建立步驟與現有憑證建立步驟相符 程序。在 BeginCreatePublicKeyCredentialRequest 中使用 如果要求是針對密碼金鑰,請handleCreatePasskeyQuery()

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

handleCreatePasskeyQuery() 中加入 BiometricPromptData,其中包含 CreateEntry 類別:

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

憑證提供者應在 BiometricPromptData 例項中明確設定 allowedAuthenticator 屬性。如未設定此屬性,值 預設值為 DEVICE_WEAK。視需要設定選用的 cryptoObject 屬性 符合用途的工作模型

啟用單一登入密碼金鑰登入流程

與密碼金鑰建立流程類似,這項流程會按照處理使用者登入的現有設定進行。在 BeginGetPublicKeyCredentialOption 下方,使用 populatePasskeyData() 收集驗證要求的相關資訊:

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

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

  // ... other logic as needed
}

CreateEntry 類似,BiometricPromptData 例項會設為 PublicKeyCredentialEntry 執行個體。如果未明確設定,allowedAuthenticator 預設為 BIOMETRIC_WEAK

PublicKeyCredentialEntry(
  // other properties...

  biometricPromptData = BiometricPromptData(
    allowedAuthenticators = allowedAuthenticator
  )
)

處理憑證項目選取作業

處理密碼金鑰建立登入時的密碼金鑰選取作業時,請視情況呼叫 PendingIntentHandler's retrieveProviderCreateCredentialRequestretrieveProviderGetCredentialRequest。這些傳回物件 ,其中包含提供者所需的中繼資料。舉例來說 選取密碼金鑰建立項目,如下所示更新程式碼:

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.authenitcationError
    // Process the error
}

  // Other logic...
}

這個範例包含生物識別流程成功的相關資訊。也包含其他憑證資訊。如果流程失敗,請使用 biometricPromptResult.authenticationError 底下的錯誤代碼做出決策。biometricPromptResult.authenticationError.errorCode 傳回的錯誤代碼與 androidx.biometric 程式庫中定義的錯誤代碼相同,例如 androidx.biometric.BiometricPrompt.NO_SPACEandroidx.biometric.BiometricPrompt.UNABLE_TO_PROCESSandroidx.biometric.BiometricPrompt.ERROR_TIMEOUT 等。 authenticationError 也會包含與 能在 UI 上顯示的 errorCode

同樣地,在 retrieveProviderGetCredentialRequest 期間擷取中繼資料。 檢查生物特徵辨識流程是否為 null。如果是,請將自己的生物特徵辨識設為 並進行驗證。這與 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.authenitcationError
    // Process the error
}

  // Other logic...