TouchID Authentication

1k Views Asked by At

I have an app written in Swift that uses LocalAuthentication to allow users to log-in to the app with TouchID or phone passcode. I have set a notification observer to launch authentication block whenever app comes to Foreground so the user can re-authenticate. Everything works great and TouchID alert is displayed when the app comes to foreground after I press the home button and send the app to the background, but the problem arises after I navigate to another app from my app (such as any other app notification appears at the top and it's clicked to navigate to it) and then want to return to my app:

Go back to my app button in top bar

When my app returns to foreground, TouchID alert is not displayed as it should. Instead, my app looks as if it's not authenticated (empty tableView) and after I lock (deauthenticate) and unlock (authenticate), in order to force authentication, I get series of alerts stating "Canceled by another authentication" and at least 2 TouchID alerts.

It seams to me that the TouchID alert is being fired, but remains hidden and is then canceled by lock/unlock action to force another one.

Is there anyone that had similar problem?

Here is some code related to this problem:

override func viewDidLoad() {
    super.viewDidLoad()
    defaults.set(false, forKey: "authenticated")
    NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationWillEnterForeground, object: nil, queue: nil, using: {_ in

            self.navigationController?.popToRootViewController(animated: true)
            self.accounts = []
            self.tableView.reloadData()
            self.authenticateUser()
            self.defaults.set(false, forKey: "authenticated")
    })}

func authenticateUser() {
    let context = LAContext()
    var error: NSError?
    let reason = "Identify yourself"

    if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
        print("canEvaluateWithTouchID")
        context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason:
            reason, reply: {success, error in
            print("EvaluateWithTouchID")
            // Touch ID
            DispatchQueue.main.async {
                if success {
                    self.navigationItem.rightBarButtonItem?.isEnabled = true
                    self.searchBar.isUserInteractionEnabled = true
                    self.fetchFromCoreData()
                    self.defaults.set(true, forKey: "authenticated")
                    print("Success: TouchID")
                } else {
                    self.defaults.set(false, forKey: "authenticated")
                    self.accounts = []
                    self.navigationItem.rightBarButtonItem?.isEnabled = false
                    self.searchBar.isUserInteractionEnabled = false
                    self.lockButton.title = "Unlock"
                    self.tableView.reloadData()

                    switch error!._code {
                    case Int(kLAErrorAuthenticationFailed):
                        self.loginAlert(message: error!.localizedDescription)
                        print("AuthFailed1")
                    case Int(kLAErrorUserCancel):
                        self.loginAlert(message: error!.localizedDescription)
                        print("UserCanceled1")
                    case Int(kLAErrorBiometryNotEnrolled):
                        self.loginAlert(message: error!.localizedDescription)
                        print("biometry1")
                    case Int(kLAErrorPasscodeNotSet):
                        self.userFallbackPasswordAlertWith(error: error!)
                        print("PassNotSet1")
                    case Int(kLAErrorSystemCancel):
                        self.loginAlert(message: error!.localizedDescription)
                          print("SystemCancel1")
                    case Int(kLAErrorUserFallback):
                        self.userFallbackPasswordAlertWith(error: error!)
                          print("UserFallback1")
                    default:
                        self.userFallbackPasswordAlertWith(error: error!)
                          print("default1")
                    }
                }
            }
        })
    } else {
        print("canEvaluateWithPasscode")
        context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason, reply: {success, error in
            print("EvaluateWithPasscode")
            //No Touch ID
            DispatchQueue.main.async {

                if success {
                    self.navigationItem.rightBarButtonItem?.isEnabled = true
                    self.searchBar.isUserInteractionEnabled = true
                    self.lockButton.title = "Lock"
                    self.fetchFromCoreData()
                    self.defaults.set(true, forKey: "authenticated")

                } else {
                    self.defaults.set(false, forKey: "authenticated")
                    self.accounts = []
                    self.navigationItem.rightBarButtonItem?.isEnabled = false
                    self.searchBar.isUserInteractionEnabled = false
                    self.lockButton.title = "Unlock"
                    self.tableView.reloadData()
                    switch error!._code{
                    case Int(kLAErrorAuthenticationFailed):
                        self.loginAlert(message: error!.localizedDescription)
                        print("AuthFailed2")
                    case Int(kLAErrorUserCancel):
                        self.loginAlert(message: error!.localizedDescription)
                        print("UserCanceled2")
                    case Int(kLAErrorBiometryNotEnrolled):
                        self.loginAlert(message: error!.localizedDescription)
                        print("biometry2")
                    case Int(kLAErrorPasscodeNotSet):
                        self.userFallbackPasswordAlertWith(error: error!)
                        print("PassNotSet2")
                    case Int(kLAErrorSystemCancel):
                        self.loginAlert(message: error!.localizedDescription)
                        print("SystemCancel2")
                    case Int(kLAErrorUserFallback):
                        self.userFallbackPasswordAlertWith(error: error!)
                        print("UserFallback2")
                    default:
                        self.userFallbackPasswordAlertWith(error: error!)
                        print("default2")
                    }
                }
            }
        })
    }
}

@IBAction func lockButton(_ sender: UIBarButtonItem) {
    accounts = []
    tableView.reloadData()
    if lockButton.title == "Unlock" {
        authenticateUser()
    }
    if lockButton.title == "Lock" {
        lockButton.title = "Unlock"
    }
    defaults.set(false, forKey: "authenticated")
}

Any input would be appreciated. Thanks.

0

There are 0 best solutions below