[Android] 안드로이드 생체 인식 인증 구현해보기!

대다수의 앱에서 로그인이나 중요한 인증이 필요한 경우 비밀번호가 아닌 얼굴 인식, 지문 인식 같은 생체 인식 인증을 요청하는 방법을 사용하는데요, 오늘은 안드로이드 프로젝트에 어떻게 적용하는지 공부해보려고 합니다!

어떤 라이브러리를 사용하고 어떻게 프로젝트에 적용하는지 알아보도록 하겠습니다.


어떤 라이브러리를 사용하는가?

안드로이드 생체 인식을 위한 라이브러리는 두 가지가 존재합니다. 바로 FingerPrintManagerBiometricPrompt 입니다. 

- FingerPrintManager : API 레벨  23 ~27

- BiometricPrompt : API 레벨 28 이상 

 

AndroidX 생체 인식 라이브러리를 사용하기 전에는 자체 인증 UI를 만들어야 했지만, AndroidX로 이전을 통해 표준적인 UI와 단일 메서드 호출을 통해 해당 기기가 생체 인증을 지원하는지 확인할 수 있습니다.

 

 

CryptoObject를 이용한 BiometricPrompt

앱에서는 BiometricPrompt를 이용하여 두 가지 방식으로 기능을 사용할 수 있습니다. CryptoObject를 사용하는 경우와 사용하지 않는 경우입니다. 하지만 은행 앱이나 민감한 데이터가 들어있는 앱에서는 조금 더 강력하게 인증 방식을 구현하기 위해 CryptoObject를 함께 사용한다고 합니다. (구글에서도 CryptoObject를 함께 사용하는 방식을 권장합니다)

 

그럼 이제 프로젝트에 적용하는 방버에 대해 알아보도록 하겠습니다!

 

프로젝트에 적용해보기

1. BiometricPrompt  Gradle 추가

https://developer.android.com/jetpack/androidx/releases/biometric

    def biometric_version = '1.1.0'
    implementation "androidx.biometric:biometric:$biometric_version"

 

2. 퍼미션 추가하기

<uses-permission android:name="android.permission.USE_BIOMETRIC"/>

 

3. 디바이스 생체 인식 가능 여부 확인하기

    private fun checkAvailableAuth() {
        val biometricManager = BiometricManager.from(this)
        when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK)) {
            BiometricManager.BIOMETRIC_SUCCESS -> {
                //  생체 인증 가능
            }
            BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
                //  기기에서 생체 인증을 지원하지 않는 경우
            }
            BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
                Log.d("MainActivity", "Biometric facility is currently not available")
            }
            BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
                //  생체 인식 정보가 등록되지 않은 경우
            }
            else -> {
                //   기타 실패
            }
        }
    }

BiometricManager를 이용하여 해당 디바이스가 생체인증이 가능한지 여부를 판단할 수 있습니다. 

 

4. BiometricPrompt  Callback 정의하기

BiometricPrompt는 Activity나 Fragment 생명주기에 맞추어 onCreate()나 onCreateView()에서 인스턴스화 해야 합니다. BiometricPrompt를 생성하는 방식은 다음과 같습니다.

    private fun createBiometricPrompt(): BiometricPrompt {
        val executor = ContextCompat.getMainExecutor(this)

        val callback = object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)
                Log.d(TAG, "$errorCode :: $errString")
                if (errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
                    //TODO - 생체 인식이 안될 경우 비밀번호 입력할 수 있도록 기능 추가
                }
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                Log.d(TAG, "Authentication failed for an unknown reason")
            }

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
                Log.d(TAG, "Authentication was successful")
                // Proceed with viewing the private encrypted message.
                showEncryptedMessage(result.cryptoObject)
            }
        }

        return BiometricPrompt(this, executor, callback)
    }

BiometricPrompt.AuthenticationCallback() 콜백 리스너를 등록하여 Error가 발생한 경우, 인증에 성공한 경우, 실패한 경우에 따라서 코드를 작성할 수 있습니다.

 

5. PromptInfo  생성하기

이제 PromptInfo를 생성하여 해당 생체 인증을 왜 사용하는지에 대한 부가 설명, 타이틀 등을 설정하고 불필요한 환경 요소들을 설정할 수 있습니다. 또한, setAllowedAuthenticators()를 사용하여 앱에서 지원하는 인증 유형을 선언할 수 있습니다.

val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric login for my app")
        .setSubtitle("Log in using your biometric credential")
        .setAllowedAuthenticators(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
        .build()

예를 들어 다음과 같이 설정한다면 setAllowedAuthenticators()에 BIOMETRIC_STRONGDEVICE_CREDENTIAL로 설정되어 있는 것을 확인할 수 있는데요, 이렇게 설정하면 지문인식과 PIN번호 입력으로 인증하는 것을 확인할 수 있습니다.

BIOMETRIC_STRONG : Android 호환성 정의 페이지에서 정의한 클래스 3생체 인식을 사용하는 인증

BIOMETRIC_WEAK : Android 호환성 정의 페이지에서 정의한 클래스 2생체 인식을 사용하는 인증

DEVICE_CREDENTIAL : 화면 잠금 사용자 인증 정보를 사용하는 인증 - 사용자의 PIN, 패턴 또는 비밀번호

를 의미하며 앱에서 제공할 인증 유형을 선택하면 됩니다.

setAllowedAuthenticators(BIOMETRIC_WEAK or DEVICE_CREDENTIAL)

다음과 같이 선택하면 지문인식과 얼굴인식을 이용하여 생체 인증을 이용할 수 있습니다.

 

이외에도 setNegativeButtonText() 메서드를 이용하여 Negative 버튼 기능을 설정할 수 있습니다. 하지만 해당 메서드는 setAllowedAuthenticators()와 함께 사용하지 못하며 둘 중 하나만 적용할 수 있다는 것을 알아두어야 합니다.

 

 

5. 생체 인식 실행하기

        btn_login.setOnClickListener { 
            biometricPrompt.authenticate(promptInfo)
            biometricPrompt.authenticate(promptInfo, cryptoObject) //cryptoObject 사용
        }

이제 다음과 같이 설정한 promptInfo를 전달하며 로그인 버튼을 눌렀을 때 생체 인식이 실행될 수 있도록 구현할 수 있습니다. 해당 코드를 보면 authenticate메서드 안에 cryptoObject를 함께 전달하는 경우가 있습니다. 앞서 설명했던 강력한 보안을 위해 추가로 cryptoObject를 생성하고 함께 전달하는 방법을 이용할 수 있습니다.

 

완성물

 

 

 

마무리

Android에서 제공하는 라이브러리를 통해 간단하게 생체 인식 인증 방법에 대해 알아보았습니다. 로그인 기능을 구현하거나 인증 기능을 구현할 때 함께 사용해보면 좋을 것 같다는 생각이 들었습니다! 저도 다음 프로젝트에 로그인 기능이 있다면 적용해보도록 하겠습니다~!