I need to implement touch ID and have to show alert to user for authentication attempts left. Below code Im using.
reply block not getting called after one wrong authentication attempt. Its getting called after 3 continues wrong authentication attempt. Is there any way to get count of wrong authentication attempts..?
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = #"Touch ID Test to show Touch ID working in a custom app";
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"Success" sender:nil];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
NSLog(#"Switch to fall back authentication - ie, display a keypad or password entry box");
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:authError.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
});
}
I went through the documentation, it is not possible to show alert in each failed attempt. Just refer the documentation
LocalAuthentication in iOS. You can show alerts at different error cases. After 3rd failed attempt LAError.authenticationFailed will be called and after 5th failed attempt LAError.touchIDLockout will be called. You can display the alerts here. For more info refer Apple LAError documentation.
Related
This question already has answers here:
How can I differentiate between fingerprints with TOUCH ID [duplicate]
(1 answer)
Know which user logging into app depending on touchid in iOS
(1 answer)
Closed 5 years ago.
I am working on an application which uses Touch ID. I have integrated the Touch ID into the app to authenticate the user to access some app elements and it works fine.
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:#"Are you the device owner?" reply:^(BOOL success, NSError *error) {
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"There was a problem verifying your identity."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
return;
}
NSLog(#"%#",context);
if (success) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Success"
message:#"You are the device owner!"
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"You are not the device owner."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
}];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device cannot authenticate using TouchID."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
}
Now, suppose if there are 2 fingerprints like Alice and Bob. Authentication works for both the fingerprints without any issue.
But I need to show which fingerprint user has been authenticated.
Is there any way to access it?
How would you even know which user is which? They don't have names, and there's no identity management substrate built into iOS.
You just have to trust that if the person who has added fingerprints is trusting someone else by adding their fingerprint, they gain access to everything TouchID authorizes.
I'm using the following logic to check if touchID is available on iPhone and based on the returned value, I direct the user to enroll in touchID or navigate them to setup a PIN. It works fine in the happy path, but if I have even one fingerprint enrolled but have disabled touchID option from iPhone system settings, then it still returns true and navigates user to setup touchID. If I remove all fingerprints, then it works as expected by returning false and navigating to PIN screen.
- (BOOL) isTouchIDAvailable {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
if (![myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
NSLog(#"Touch ID checking error: %#", [authError localizedDescription]);
return NO;
}
return YES;
}
I've referred to some questions on stack and apple dev docs
Not sure what I'm missing? Appreciate any help. Thanks in advance :)
let context = LAContext()
var error: NSError?
if #available(iOS 9.0, *) {
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
//this is for success
}else{
//error.description for type error LAError.biometryLockout, .biometryNotEnrolled and other errors
}
}
it's not possible. if you have TouchID, you have touchID. But if you want, you can disabled with programaticly. Look at the below code snippet to check touchID is aviable or not.
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = [NSString stringWithFormat:#"Login With your fingerprint with : %#",username];
if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
// [self performSegueWithIdentifier:#"Success" sender:nil];
[self loginWithFingerprint];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:error.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
*/
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:authError.description
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alertView show];
*/
// Rather than show a UIAlert here, use the error to determine if you should push to a keypad for PIN entry.
});
}
I'm trying to set up an anonymous login so my users don't have to create an account an account on the eJabberd server to use the chat room. The configuration for the server in the ejabberd.cfg is:
{host_config, "bubble", [{auth_method, anonymous},
{anonymous_protocol, login_anon}]}.
My method to connect the client to the XMPPStream:
- (BOOL)connect {
[self setupStream];
if (![self.xmppStream isDisconnected]) {
return YES;
}
if (![PFUser currentUser]) {
return NO;
}
NSString *currentUserId = [NSString stringWithFormat:#"%##bubble",[PFUser currentUser].objectId];
[self.xmppStream setMyJID:[XMPPJID jidWithString:currentUserId]];
self.xmppStream.hostName = kJABBER_HOSTNAME;
NSError *error = nil;
if (![self.xmppStream connectWithTimeout:10 error:&error]) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:[NSString stringWithFormat:#"Can't connect to server %#", [error localizedDescription]]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
return NO;
}
return YES;
}
As well as the xmppStreamDidConnect method:
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
self.isOpen = YES;
NSError *error = nil;
if(![self.xmppStream authenticateAnonymously:&error]) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error"
message:[NSString stringWithFormat:#"Can't connect to server %#", [error localizedDescription]]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
}
}
When I try to login into the server, it keep on getting "The server does no support anonymous authentication".
Not sure what I'm doing wrong here, please let me know your thoughts.
From the XMPPFramework documentation:
If you wish to use anonymous authentication, you should still set myJID prior to calling connect. You can simply set it to something like "anonymous#domain", where "domain" is the proper domain. After the authentication process, you can query the myJID property to see what your assigned JID is.
Make sure that the settings on the server allow anonymous login as well.
If you don't have access to the serve configuration you can still check if the server allows anonymous login using something like:
- (void)xmppStreamDidConnect:(XMPPStream*)sender
{
self.isXmppConnected = YES;
if ([self.xmppStream supportsAnonymousAuthentication]) {
NSError* error = nil;
//the server does support anonymous auth
[self.xmppStream authenticateAnonymously:&error];
}
else {
NSLog(#"The server does not support anonymous authentication");
}
}
Be sure to place it in the didConnect delegate method, as it needs to be connected first.
I'm working on adding the LocalAuthentication framework to allow users to authenticate with a fingerprint on comparable devices. Everything works properly, but when a user is authenticated with their finger print it takes between 10-15 seconds for the proper segue to be performed, is this typical, or is there something wrong with the way I'm authenticating a user?
Code:
-(void)viewDidLoad { [super viewDidLoad]; [self.view setBackgroundColor:[NPSColor NPSBackgroundColor]];
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Register" style:UIBarButtonItemStylePlain target:self action:#selector(onRegisterTapped)]; self.navigationItem.rightBarButtonItem = anotherButton;
LAContext *context = [[LAContext alloc] init];
NSError *error = nil; if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:#"Login?" reply:BOOL success, NSError *error {
if (error) {
}
if (success) {
[self performSegueWithIdentifier:#"loginSeg" sender:self];
} else {
}
}];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Your device cannot authenticate using TouchID."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alert show];
} }
So it may be that performing a segue has to do with a view action which should mainly be performed on the main thread. I'm not too sure but it could very well be the evaluatePolicy method is performed on a background thread. If this is the case, you would want to throw your performSegue on the main thread.
To do so, use this:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"loginSeg" sender:self];
});
When I submit with empty textbox page is change and UIAlertView show after that, but I want to UIAlertView show in current page and page can not change (Stay on Signin Viewcontroller).
Thanks
- (IBAction)btnSignin:(id)sender {
[PFUser logInWithUsernameInBackground:_txtSigninUsername.text password:_txtSigninPassword.text block:^(PFUser *user, NSError *error) {
if (!error) {
NSLog(#"Login user!");
_txtSigninUsername.text = nil;
_txtSigninPassword.text = nil;
[self performSegueWithIdentifier:#"Signin" sender:self];
}
if (error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"ooops!" message:#"Sorry we had a problem logging you in" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}];
}
My Storyboard :
You're performing the Segue with "Signin" identifier with the condition "error".
So when there's an error first your code performs the segue and then performs the error message.
Change "!error" with "user" and it should hopefully work. Let me know.