생체 인식 메시지를 통해 원탭 패스키 생성 및 로그인을 통합합니다.

Android 15에서 인증 관리자는 사용자 인증 정보 생성 및 검색을 위한 원탭 흐름을 지원합니다. 이 흐름에서는 생성 중인 사용자 인증 정보 또는 사용 중인 사용자 인증 정보의 정보가 생체 인식 메시지에 더 많은 옵션의 진입점과 함께 직접 표시됩니다. 이 간소화된 프로세스를 통해 사용자 인증 정보 생성 및 검색 프로세스가 더 효율적이고 간소화됩니다.

요구사항:

  • 사용자의 기기에 생체 인식이 설정되어 있고 사용자가 애플리케이션에 대한 인증을 위해 생체 인식을 허용합니다.
  • 로그인 흐름의 경우 이 기능은 해당 계정에 여러 사용자 인증 정보 (예: 패스키 및 비밀번호)가 있는 경우에도 단일 계정 시나리오에만 사용 설정됩니다.

패스키 생성 흐름에서 한 번 탭하여 사용 설정

이 메서드의 생성 단계는 기존 사용자 인증 정보 생성 프로세스와 일치합니다. 패스키에 관한 요청인 경우 BeginCreatePublicKeyCredentialRequest 내에서 handleCreatePasskeyQuery()를 사용하여 요청을 처리합니다.

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

handleCreatePasskeyQuery()에서 CreateEntry 클래스와 함께 BiometricPromptData를 포함합니다.

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 retrieveProviderCreateCredentialRequest 또는 retrieveProviderGetCredentialRequest를 호출합니다. 이러한 객체는 제공자에게 필요한 메타데이터가 포함된 객체를 반환합니다. 예를 들어 패스키 생성 항목 선택을 처리할 때 다음과 같이 코드를 업데이트합니다.

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_SPACE, androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS, androidx.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...