【问题标题】:iOS - User Authentication Function That Returns BooliOS - 返回 Bool 的用户身份验证函数
【发布时间】:2015-10-19 14:02:34
【问题描述】:

最终,我想要的是一个函数(或者可能是一个单独的类中的函数),它提示用户通过 TouchID 进行身份验证,然后是密码,如果其中任何一个成功,则返回一个真正的布尔值。

我已经弄清楚了身份验证,但是我无法让函数返回布尔值,这大致是我目前所拥有的:

认证用户功能:

func authenticateUser() -> Bool {

        let context = LAContext()
        var error: NSError?
        let reasonString = "Authentication is needed to access your places."

        if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) {

            context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success, policyError) -> Void in

                if success {

                    print("touchID authentication succesful")

                } else {

                    switch policyError!.code {

                    case LAError.UserFallback.rawValue:

                        print("User selected to enter password.")

                        NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                            self.showPasswordAlert()
                        })

                    default:

                        print("Authentication failed! :(")

                    }
                }

            })

        } else {

            print(error?.localizedDescription)

            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                self.showPasswordAlert()
            })
        }

        return true

    }

现在它只是设置为返回 true 用于测试目的。但是,只要身份验证成功,我希望它返回 true。我不能将返回值放在context.evaluatePolicy 中,因为它在块方法中。还有另一种方法可以做我想做的事吗?还是我以完全错误的方式处理这个问题?

另外,这里是我的showPasswordAlert函数供参考:

func showPasswordAlert() {

        let alertController = UIAlertController(title: "Passcode", message: "Please enter your passcode.", preferredStyle: .Alert)

        let defaultAction = UIAlertAction(title: "OK", style: .Default) { (action) -> Void in

            if let textField = alertController.textFields?.first as UITextField? {

                if let passcode = self.keychainWrapper.myObjectForKey("v_Data") as? String {

                    if textField.text == passcode {

                        print("Authentication successful! :) ")

                    } else {


                    }

                }

            }

        }

        let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)

        alertController.addAction(defaultAction)

        alertController.addAction(cancelAction)

        alertController.addTextFieldWithConfigurationHandler { (textField) -> Void in

            textField.placeholder = "Enter passcode..."
            textField.textAlignment = NSTextAlignment.Center
            textField.secureTextEntry = true
            textField.keyboardType = UIKeyboardType.NumberPad

        }

        self.presentViewController(alertController, animated: true, completion: nil)

    }

所以在我的脑海中,我的想法是:showPasswordAlert 也可以将一个真正的布尔值返回给authenticateUser,然后这又会返回一个真正的布尔值到 authenticateUser 函数被调用的位置。我知道有一种更简单的方法可以做到这一点,但我现在只想让它工作。

【问题讨论】:

  • 相关排序:Throwing Exceptions in a Block Method 截至此评论,没有接受或正面评分的答案(其中 0 不是“正面”)
  • 那么简短的回答是因为它在闭包内,所以不能按照我期望的方式完成?
  • 不确定。也许有人会想出什么办法。

标签: ios swift authentication touch-id


【解决方案1】:

因此,经过多次反复试验,我想出了目前最适合我的解决方案。

似乎从evaluatePolicy 和 co.异步运行,您不能从它们返回变量访问变量。但是,您可以从这些块中调用 selectors(我不知道为什么会这样)。

所以在写这篇文章时我目前的解决方案是这样调用验证函数:

func authenticateUserWithAction(actionSelector: Selector, object: AnyObject){}

我向它传递了一个动作(在类的其他地方声明,但基本上是在身份验证成功时您想要做什么)和一个对象。该对象只是以防操作需要将某些内容传递给函数。因此,例如在我的应用程序中,在身份验证之后会显示一个 viewController,并且该 viewController 上的一个对象被设置为原始 viewController 中的一个对象。此对象在身份验证函数中传递。

从身份验证用户函数中,我可以调用authenticateUserWithPasscode(actionSelector: Selector, object: AnyObject),它采用与原始身份验证函数相同的操作和对象。

动作和对象在链中向下传递,直到用户通过身份验证并被执行。

总体上相当 hacky 代码,但它似乎对我来说工作正常。

【讨论】:

    【解决方案2】:

    也有这个问题,我最终制作了一个名为 Authentication 的结构,它有一个静态函数 authenticate ,它从你调用它的地方传递给视图控制器和一个回调函数:

    import LocalAuthentication
    import UIKit
    
    struct Authentication {
    static func authenticate(viewController: UIViewController, callback: 
    @escaping (Bool) -> ()) {
        let context = LAContext()
        var error: NSError?
    
        if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
            let reason = "Please Authenticate"
    
            context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) {
                [weak viewController] success, authenticationError in
    
                guard let viewController = viewController else {
                    return
                }
    
                DispatchQueue.main.async {
                    if success {
                        callback(true)
                    } else {
                        let ac = UIAlertController(title: "Authentication failed", message: "Please try again", preferredStyle: .alert)
                        ac.addAction(UIAlertAction(title: "OK", style: .default))
                        viewController.present(ac, animated: true)
                        callback(false)
                    }
                }
            }
        } else {
            let ac = UIAlertController(title: "Touch ID not available", message: "Your device is not configured for Touch ID.", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "OK", style: .default))
            viewController.present(ac, animated: true)
            callback(false)
        }
    }
    }
    

    然后调用它:

    Authentication.authenticate(viewController: parentViewController, callback: {
            [weak self] (authenticated: Bool) in
            if authenticated {
                self?.yourFunctionHere()
            }
        })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-18
      • 2011-11-14
      • 1970-01-01
      • 1970-01-01
      • 2012-12-23
      • 2021-01-01
      • 2021-08-23
      • 1970-01-01
      相关资源
      最近更新 更多