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

Android 15에서 인증 관리자는 사용자 인증 정보의 단일 탭 흐름을 지원합니다. 생성 및 가져오기에 사용됩니다. 이 흐름에서는 생성 또는 사용 중인 모든 정보가 생체 인식 프롬프트에 더 많은 옵션으로 이동할 수 있는 진입점이 있습니다 이 간소화된 프로세스를 통해 사용자 인증 정보 생성 및 검색 프로세스가 더 효율적이고 간소화됩니다.

요구사항:

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

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

이 메서드의 생성 단계는 기존 사용자 인증 정보 생성과 일치합니다. 절차에 따라 다릅니다. 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 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...