iOS - 返回Bool

时间:2015-10-19 14:02:35

标签: ios swift authentication touch-id

最终,我想要的是一个函数(或者可能是一个单独的类中的函数),它提示用户通过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返回一个真正的布尔值,然后这将返回一个真正的布尔值到{{1}正在调用函数。我知道有一种更简单的方法可以做到这一点,但我现在想让它工作。

2 个答案:

答案 0 :(得分:0)

经过多次试验和错误,我现在想出的最佳解决方案是什么。

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

所以我写这篇文章时的当前解决方案就是调用authenticate函数:

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

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

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

操作和对象沿着链传递,直到用户通过身份验证并执行。

整体上非常hacky代码,但它似乎对我来说很好。

答案 1 :(得分:0)

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

$appPath = "C:\SomeFolder"

$Acl = (Get-Item $appPath).GetAccessControl('Access') 

$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule("NETWORK SERVICE", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")

$Acl.SetAccessRule($Ar)

Set-Acl $appPath $Acl

然后调用它:

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)
    }
}
}