Xamarin.iOS에서 터치 ID 및 얼굴 ID 사용

iOS는 두 가지 바이오 메트릭 인증 시스템을 지원합니다.

  1. 터치 ID 는 홈 단추 아래에 지문 센서를 사용합니다.
  2. 얼굴 ID 는 전면 카메라 센서를 사용하여 얼굴 스캔으로 사용자를 인증합니다.

터치 ID는 iOS 7 및 iOS 11의 Face ID에 도입되었습니다.

이러한 인증 시스템은 Secure Enclave라는 하드웨어 기반 보안 프로세서를 사용합니다. Secure Enclave는 얼굴 및 지문 데이터의 수학적 표현을 암호화하고 이 정보를 사용하여 사용자를 인증합니다. Apple에 따르면 얼굴 및 지문 데이터는 장치를 떠나지 않으며 iCloud에 백업되지 않습니다. 앱은 로컬 인증 API를 통해 Secure Enclave와 상호 작용하며 얼굴 또는 지문 데이터를 검색하거나 Secure Enclave에 직접 액세스할 수 없습니다.

보호된 콘텐츠에 대한 액세스를 제공하기 전에 앱에서 터치 ID 및 얼굴 ID를 사용하여 사용자를 인증할 수 있습니다.

로컬 인증 컨텍스트

iOS의 생체 인식 인증은 클래스의 인스턴스인 로컬 인증 컨텍스트 개체를 LAContext 사용합니다. 클래스를 LAContext 사용하면 다음을 수행할 수 있습니다.

  • 바이오 메트릭 하드웨어의 가용성을 확인합니다.
  • 인증 정책을 평가합니다.
  • 액세스 제어를 평가합니다.
  • 인증 프롬프트를 사용자 지정하고 표시합니다.
  • 인증 상태를 다시 사용하거나 무효화합니다.
  • 자격 증명을 관리합니다.

사용 가능한 인증 방법 검색

샘플 프로젝트에는 .에 AuthenticationView 의해 지원되는 항목이 AuthenticationViewController포함됩니다. 이 클래스는 사용 가능한 인증 방법을 검색하도록 메서드를 재정의 ViewWillAppear 합니다.

partial class AuthenticationViewController: UIViewController
{
    // ...
    string BiometryType = "";

    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
        unAuthenticatedLabel.Text = "";

        var context = new LAContext();
        var buttonText = "";

        // Is login with biometrics possible?
        if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out var authError1))
        {
            // has Touch ID or Face ID
            if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
            {
                context.LocalizedReason = "Authorize for access to secrets"; // iOS 11
                BiometryType = context.BiometryType == LABiometryType.TouchId ? "Touch ID" : "Face ID";
                buttonText = $"Login with {BiometryType}";
            }
            // No FaceID before iOS 11
            else
            {
                buttonText = $"Login with Touch ID";
            }
        }

        // Is pin login possible?
        else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out var authError2))
        {
            buttonText = $"Login"; // with device PIN
            BiometryType = "Device PIN";
        }

        // Local authentication not possible
        else
        {
            // Application might choose to implement a custom username/password
            buttonText = "Use unsecured";
            BiometryType = "none";
        }
        AuthenticateButton.SetTitle(buttonText, UIControlState.Normal);
    }
}

ViewWillAppear 메서드는 UI가 사용자에게 표시하려고 할 때 호출됩니다. 이 메서드는 새 인스턴스를 LAContext 정의하고 이 메서드를 CanEvaluatePolicy 사용하여 바이오 메트릭 인증이 사용되는지 여부를 확인합니다. 그렇다면 시스템 버전과 BiometryType 열거형을 검사 사용할 수 있는 바이오 메트릭 옵션을 결정합니다.

바이오 메트릭 인증을 사용하지 않는 경우 앱은 PIN 인증으로 대체하려고 시도합니다. 바이오 메트릭 또는 PIN 인증을 사용할 수 없는 경우 디바이스 소유자는 보안 기능을 사용하도록 설정하지 않았으며 로컬 인증을 통해 콘텐츠를 보호 할 수 없습니다.

사용자 인증

샘플 프로젝트에는 AuthenticationViewController 사용자 인증을 AuthenticateMe 담당하는 메서드가 포함되어 있습니다.

partial class AuthenticationViewController: UIViewController
{
    // ...
    string BiometryType = "";

    partial void AuthenticateMe(UIButton sender)
    {
        var context = new LAContext();
        NSError AuthError;
        var localizedReason = new NSString("To access secrets");

        // Because LocalAuthentication APIs have been extended over time,
        // you must check iOS version before setting some properties
        context.LocalizedFallbackTitle = "Fallback";

        if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
        {
            context.LocalizedCancelTitle = "Cancel";
        }
        if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
        {
            context.LocalizedReason = "Authorize for access to secrets";
            BiometryType = context.BiometryType == LABiometryType.TouchId ? "TouchID" : "FaceID";
        }

        // Check if biometric authentication is possible
        if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError))
        {
            replyHandler = new LAContextReplyHandler((success, error) =>
            {
                // This affects UI and must be run on the main thread
                this.InvokeOnMainThread(() =>
                {
                    if (success)
                    {
                        PerformSegue("AuthenticationSegue", this);
                    }
                    else
                    {
                        unAuthenticatedLabel.Text = $"{BiometryType} Authentication Failed";
                    }
                });

            });
            context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason, replyHandler);
        }

        // Fall back to PIN authentication
        else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out AuthError))
        {
            replyHandler = new LAContextReplyHandler((success, error) =>
            {
                // This affects UI and must be run on the main thread
                this.InvokeOnMainThread(() =>
                {
                    if (success)
                    {
                        PerformSegue("AuthenticationSegue", this);
                    }
                    else
                    {
                        unAuthenticatedLabel.Text = "Device PIN Authentication Failed";
                        AuthenticateButton.Hidden = true;
                    }
                });

            });
            context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, localizedReason, replyHandler);
        }

        // User hasn't configured any authentication: show dialog with options
        else
        {
            unAuthenticatedLabel.Text = "No device auth configured";
            var okCancelAlertController = UIAlertController.Create("No authentication", "This device does't have authentication configured.", UIAlertControllerStyle.Alert);
            okCancelAlertController.AddAction(UIAlertAction.Create("Use unsecured", UIAlertActionStyle.Default, alert => PerformSegue("AuthenticationSegue", this)));
            okCancelAlertController.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Cancel, alert => Console.WriteLine("Cancel was clicked")));
            PresentViewController(okCancelAlertController, true, null);
        }
    }
}

로그인 AuthenticateMe 단추를 탭하는 사용자에 대한 응답으로 메서드가 호출됩니다. 새 LAContext 개체가 인스턴스화되고 디바이스 버전이 검사 로컬 인증 컨텍스트에서 설정할 속성을 결정합니다.

CanEvaluatePolicy 메서드는 바이오 메트릭 인증을 사용하는 경우 검사, 가능한 경우 PIN 인증으로 대체하고, 인증을 사용할 수 없는 경우 마지막으로 보안되지 않은 모드를 제공하기 위해 호출됩니다. 인증 방법을 사용할 수 있는 EvaluatePolicy 경우 이 메서드는 UI를 표시하고 인증 프로세스를 완료하는 데 사용됩니다.

샘플 프로젝트에는 인증에 성공하면 데이터를 표시하는 모의 데이터와 보기가 포함되어 있습니다.