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