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.authenticationError
// Process the error
}
// Other logic...
}
이 예시에는 생체 인식 흐름의 성공에 관한 정보가 포함되어 있습니다. 또한 사용자 인증 정보에 관한 기타 정보도 포함되어 있습니다. 흐름이 실패하면 biometricPromptResult.authenticationError 아래의 오류 코드를 사용하여 결정을 내립니다.
biometricPromptResult.authenticationError.errorCode의 일부로 반환되는 오류 코드는 androidx.biometric.BiometricPrompt.NO_SPACE, androidx.biometric.BiometricPrompt.UNABLE_TO_PROCESS, androidx.biometric.BiometricPrompt.ERROR_TIMEOUT 등 androidx.biometric 라이브러리에 정의된 오류 코드와 동일합니다. authenticationError에는 UI에 표시할 수 있는 errorCode와 연결된 오류 메시지도 포함됩니다.
마찬가지로 retrieveProviderGetCredentialRequest 중에 메타데이터를 추출합니다.
생체 인식 흐름이 null인지 확인합니다. 예인 경우 자체 생체 인식을 구성하여 인증합니다. 이는 작업 가져오기가 계측되는 방식과 유사합니다.
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...