Local Authentication를 이용해 생체인증 구현해보기

koi·2022년 9월 11일
4
post-thumbnail

안녕하세요~~ toma입니다🍅

프로젝트에서 생체인증 기능을 구현해야할 일이 생겨서, 구현하면서 알게된 것들을 정리해서 올리려고 합니다.

레쓰고~

📌 구현 기능 설명

제가 구현할 기능은 카카오톡의 잠금기능이랑 흡사합니다!

  • 설정에서 생체인증을 토글로 on, off 할 수 있다.
  • 토글이 켜지면 생체 인증을 받는다.
    • ✅ 인증 성공하는 경우
      이 후에 앱 런치, 포어그라운드 진입시 생체 인증을 받는다.
      앱 전환 화면인 경우 화면이 가려진다.
    • ❌ 인증 실패하는 경우
      토글이 다시 꺼진다.

우선 인증 기능을 구현하려면 LocalAuthentication 프레임워크가 필요합니다!
애플 개발자 문서를 보면서 한번 알아봅시다.

📌 Local Authentication

Overview

Authenticate users biometrically or with a passphrase they already know.
생체 인식 또는 이미 알고 있는 암호로 사용자를 인증합니다.

문서를 읽어보면, 보안상 앱이 직접적으로 인증 데이터에 접근할 수 없어도록 되어있다고 합니다. 그 대신 하드웨어 기반 보안 프로세서인 Secure Enclave가 요런 인증 데이터를 관리하고 있습니다.

그래서 앱이 LocalAuthentication을 통해서 인증을 요청하면, 앱은 인증 결과만 받을 수 있습니다.

📌 예제 코드

Overview

사용자는 이러한 인증 메커니즘을 통해 최소한의 노력으로 안전하게 장치에 액세스할 수 있기 때문에 Touch ID 및 Face ID를 좋아합니다.

Set the Face ID Usage Description

생체 인식을 사용하는 모든 프로젝트에서 앱의 Info.plist 파일에 NSFaceIDUsageDescription 키를 포함합니다. 이 키가 없으면 시스템에서 앱이 Face ID를 사용하는 것을 허용하지 않습니다. 이 키의 값은 앱이 처음으로 Face ID를 사용하려고 시도할 때 시스템이 사용자에게 표시하는 문자열입니다.

→ 대충 Info.plist에 키가 있어야 한다는 뜻이니 추가해줍니다..
여기서 키의 String 값은 사용자에게 표시되기 때문에 인증 목적이 무엇인지 명확히 밝혀야합니다~!

Create and Configure a Context

앱과 Secure Enclave 간의 상호 작용을 중개하는 LAContext 인스턴스를 사용하여 앱에서 생체 인식 인증을 수행합니다. 컨텍스트를 생성하여 시작합니다.

var context = LAContext()

컨텍스트에서 사용하는 메시징을 사용자 지정하여 흐름을 통해 사용자를 안내할 수 있습니다. 예를 들어 다양한 경고 보기에 나타나는 취소 버튼에 대한 사용자 지정 메시지를 설정할 수 있습니다.

context.localizedCancelTitle = "Enter Username/Password"

이것은 사용자가 버튼을 탭하면 일반 인증 절차로 되돌아갈 것임을 이해하는 데 도움이 됩니다.

Test Policy Availability

인증을 시도하기 전에 canEvaluatePolicy(_:error:) 메서드를 호출하여 실제로 인증할 수 있는지 테스트할 수 있습니다.

var error: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
    print(error?.localizedDescription ?? "Can't evaluate policy")

    // Fall back to a asking for username and password.
    // ...
    return
}

테스트할 LAPolicy 열거에서 값을 선택합니다. 정책은 인증이 작동하는 방식을 제어합니다.

  • LAPolicy.deviceOwnerAuthentication는 생체 인식이 실패하거나 사용할 수 없는 경우 암호로 되돌릴 수 있음을 나타냅니다.

  • 또는 장치 암호로 되돌릴 수 없는 LAPolicy.deviceOwnerAuthenticationWithBiometrics를 지정할 수 있습니다.

Evaluate a Policy

인증할 준비가 되면 이미 테스트한 것과 동일한 정책을 사용하여 evaluatePolicy(_:localizedReason:reply:) 메서드를 호출합니다.

Task {
    do {
        try await context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "Log in to your account")
        state = .loggedin
    } catch let error {
        print(error.localizedDescription)

        // Fall back to a asking for username and password.
        // ...
    }
}

Touch ID의 경우 또는 사용자가 암호를 입력하면 시스템은 메소드 호출에서 제공한 인증 이유를 표시합니다. 앱이 사용자에게 인증을 요청하는 이유에 대해 운영하는 모든 지역에 대해 현지화된 명확한 설명을 제공하는 것이 중요합니다.

Optionally, Adjust Your User Interface to Accommodate Face ID

장치에서 사용 가능한 생체 인식 종류에 따라 다른 UI를 제공할 수 있습니다.
컨텍스트의 biometryType 매개변수를 읽어 장치가 지원하는 생체 인식 유형을 테스트합니다.

faceIDLabel.isHidden = (state == .loggedin) || (context.biometryType != .faceID)

이 매개변수는 컨텍스트에서 canEvaluatePolicy(_:error:) 메소드를 한 번 이상 실행한 후에만 의미 있는 값을 포함합니다.

Provide a Fallback Alternative to Biometrics

다양한 이유로 인증이 실패하거나 사용할 수 없는 경우가 있습니다.

  • 사용자의 기기에 Touch ID 또는 Face ID가 없습니다.
  • 사용자가 생체 인식에 등록되어 있지 않거나 암호가 설정되어 있지 않습니다.
  • 사용자가 작업을 취소합니다.
  • Touch ID 또는 Face ID가 사용자를 인식하지 못합니다.
  • 이전에 invalidate() 메서드를 호출하여 컨텍스트를 무효화했습니다.

가능한 오류 조건의 전체 목록은 LAError.Code를 참조하십시오.
이 샘플 앱은 대체 인증을 구현하지 않습니다. 실제 앱에서 로컬 인증 오류가 발생하면 사용자 이름과 비밀번호를 묻는 것과 같은 고유한 인증 체계로 대체합니다. 이미 하고 있는 일에 대한 보완책으로 생체 인식을 사용하십시오. 유일한 인증 옵션으로 생체 인식에 의존하지 마십시오.

📌 구현해보기

이제 개발자 문서를 바탕으로 구현해보겠습니다.
저는 인증을 관리하는 LocalAuthenticationService 라는 이름을 가진 싱글톤을 만들어서, 안에서 인증하는 함수와 에러가 발생시 print해주는 함수를 만들었습니다.

우선 인증하는 함수만 자세히 살펴보도록 하겠습니다.

 static func execute(completion: @escaping (Bool, Error?) -> Void) {
 	let autoContext = LAContext()
 	var error: NSError?
    if autoContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
    // Face ID가 등록된 경우는 Face ID로, Touch ID가 등록된 경우는 Touch ID로 인증 실행
    // 등록되어 있지 않다면 비밀번호 인증
    autoContext.evaluatePolicy(.deviceOwnerAuthentication,
    							localizedReason: "인증이 필요합니다.") { [weak self] (response, error) in
		if let error = error { self!.onError(error: error as NSError) }
        completion(response, error) }
        } else {
            // 인증 사용 불가능한 디바이스
            print("Local Authentication is not available")
        }
    }

앞서 문서에서도 보았듯, 인증이 사용이 불가능한 경우도 분명히 있기때문에 인증을 하기 전에, 인증 가능한지 확인을 해야하는데요.
.canEvaluatePolicy(_:error:) 메서드를 통해 확인이 가능합니다.

확인 후, 인증할 준비가 되면 evaluatePolicy 메소드를 통해 인증을 진행하면 됩니다.

저는 인증할 때 메소드에 파라미터로 LAPolicy의 열거형 값으로 .deviceOwnerAuthentication를 넣어주었습니다. 생체인증이 없을 경우나 불가능할 경우 암호로 인증을 받는 방식입니다.

그리고 인증이 필요한 뷰컨트롤러에서 이렇게 처리해주면 끝.

    private func evaluateAuthentication() {
        LocalAuth.execute { response, error in
            DispatchQueue.main.async {
                if response {
                    self.pushToHomeViewController()
                } else if error != nil {
                    self.presentToAuthenticationPopup()
                }
            }
        }
    }

만약 인증이 완료되면 home으로 가게되고, 실패할 경우 인증에 실패했다는 팝업이 뜨게 됩니다.

📌 시뮬레이터로 생체인증 테스트해보기

시뮬레이터로도 FaceID 테스트가 가능한데요.
이렇게 Enrolled 해두고 Matching, Non Matching에 따라 테스트가 가능합니다!

✅ 인증 성공하는 경우

❌ 인증 실패하는 경우

요로코롬 제가 원하는대로 일단 구현이 완성되었습니다.

📌 마무리

LocalAuthentication 프레임워크를 통해 생체인증 구현을 해보았습니다! 구현하면서 되게 재밌었고, 애플이 사용자를 고려하는 부분을 많이 알 수 있었던 것 같습니다.

혹시 이렇게 App Switch(앱 전환하기) 뷰에서 사생활 보호차 화면을 가려주는 기능아시나요?

요 부분도 같이 포스팅하려고 했는데 글이 너무 길어져서.. 아쉽지만 다음 번에 포스팅하도록 하겠습니다. 틀린 부분이나 더 좋은 구현 방법이 있다면 언제든지 알려주세요~!!
읽어주셔서 감사합니다~

profile
Don't think, just do 🎸

2개의 댓글

comment-user-thumbnail
2022년 9월 16일

토마님 멋져요

답글 달기
comment-user-thumbnail
2022년 9월 16일

코딩이란건 참 어려운 것 같아요. 제가 1995년 미국에 있었을 때..

답글 달기