Я унаследовал кодовую базу со следующим классом, обеспечивающим поддержку Face / Touch ID.
Ожидаемое поведение: при успешном входе в систему через Face / Touch ID пользователь входит в систему. Это работает.
Однако, если пользователь не сможет идентифицировать лицо и решит ввести свой пароль, он будет отключен после вызова обработчика завершения. Я считаю, что выбор использования пароля вызывает
else {
self.authState = .unauthenticated
completion(.unauthenticated)
}
Как я могу вместо этого вызвать запрос пароля? Должен ли я создать вторую политику, используя LAPolicy.deviceOwnerAuthentication
и оценить ее вместо этого?
import LocalAuthentication
public enum AuthenticationState {
case unknown
case authenticated
case unauthenticated
public func isAuthenticated() -> Bool {
return self == .authenticated
}
}
public protocol TouchIDAuthenticatorType {
var authState: AuthenticationState { get }
func authenticate(reason: String, completion: @escaping (AuthenticationState) -> Void) -> Void
func removeAuthentication() -> Void
}
public protocol LAContextType: class {
func canEvaluatePolicy(_ policy: LAPolicy, error: NSErrorPointer) -> Bool
func evaluatePolicy(_ policy: LAPolicy, localizedReason: String, reply: @escaping (Bool, Error?) -> Void)
}
public class TouchIDAuthenticator: TouchIDAuthenticatorType {
public var authState: AuthenticationState = .unknown
private var context: LAContextType
private var policy = LAPolicy.deviceOwnerAuthenticationWithBiometrics
public init(context: LAContextType = LAContext()) {
self.context = context
}
public func authenticate(reason: String, completion: @escaping (AuthenticationState) -> Void) -> Void {
var error: NSError?
if context.canEvaluatePolicy(policy, error: &error) {
context.evaluatePolicy(policy, localizedReason: reason) { (success, error) in
DispatchQueue.main.async {
if success {
self.authState = .authenticated
completion(.authenticated)
} else {
self.authState = .unauthenticated
completion(.unauthenticated)
}
}
}
} else {
authState = .authenticated
completion(.authenticated)
}
}
public func removeAuthentication() -> Void {
authState = .unknown
context = LAContext() // reset the context
}
}
extension LAContext: LAContextType { }
Я должен отметить, что на симуляторе это работает должным образом, но на устройстве это не так, и я вышел из системы.