Question

I have a login page that has 2 textfields for username & password and a few buttons. I want to know that how I can use fmdb for checking if the username/password combination exists in my database? I also have another viewcontroller used for the user registeration page, having 4 textfields for username, password, email, contact number and a button to input the entered text into the database. How can I save the entered text in 4 fields to the database? Thanks in advance. Here is my code: I succeeded in entering the data into the database,in the registerViewController but I want to enter code into the "btnforgot"(forgot Password) action if the user forgets the password and/or username. I've been successful somewhat in the loginViewController too,as far as checking if the username & password match the same in the database or not,but i guess i am missing something(some code) in between.

LOGINVIEW


#import "loginViewController.h"
#import "carTypeViewController.h"
#import "registerViewController.h"
#import "FMDatabase.h"
#import "AppDelegate.h"
#import "FMDatabaseAdditions.h"
@interface loginViewController ()

@end
@implementation loginViewController
@synthesize lblPass,lblUserName,txtPass,txtUser;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; }

- (void)viewDidLoad

{
self.title = @"Enter Credentials";
username = [[NSMutableArray alloc]init];
password = [[NSMutableArray alloc]init];

[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)btnLogin:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:@"contacts.db"];
FMDatabase *database = [FMDatabase databaseWithPath:path];

[database open];

BOOL success = NO;

    NSInteger count = [database intForQuery:@"select count(*) from RegMembers where USERNAME = ? and PASSWORD = ?", username, password];

if ([txtUser.text length] == 0 || [txtPass.text length]== 0){
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:@"Kindly enter details in all fields" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
}

else if (count > 0)
{
        success = YES;

        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Welcome" message:@"Login successful" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert show];

        carTypeViewController *car = [[carTypeViewController alloc]initWithNibName:@"carTypeViewController" bundle:nil];
        [self.navigationController pushViewController:car animated:YES];

}
    else
    {
        UIAlertView *alert1 = [[UIAlertView alloc]initWithTitle:@"Kindly enter the correct credentials" message:@"Entered username or password is incorrect" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert1 show];

        txtUser.text=@"";
        txtPass.text=@"";
    }
[database close];
}
-(IBAction)removeKeyboard
{
[self.txtUser resignFirstResponder];
[self.txtPass resignFirstResponder];
}

- (IBAction)btnSignUp:(id)sender {
registerViewController *reg = [[registerViewController alloc]initWithNibName:@"registerViewController" bundle:nil];
[self.navigationController pushViewController:reg animated:YES];
}


- (IBAction)btnExit:(id)sender {
exit(1);

}

- (IBAction)btnForgotPass:(id)sender {
}

@end






REGISTERVIEW

- (void)viewDidLoad
{
self.title = @"Create Account";
[super viewDidLoad];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,      NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:@"contacts.db"];
FMDatabase *database = [FMDatabase databaseWithPath:path];

[database open];

[database executeUpdate:@"create table if not exists RegMembers (ID INTEGER NOT NULL     PRIMARY KEY AUTOINCREMENT DEFAULT 0, USERNAME TEXT UNIQUE NOT NULL , PASSWORD TEXT NOT NULL     , EMAIL TEXT NOT NULL , NUMBER TEXT  NOT NULL)"];

[database close];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

-(IBAction)removeKeyboard
{
[self.txtUname resignFirstResponder];
[self.txtPass resignFirstResponder];
[self.txtEmail resignFirstResponder];
[self.txtNumber resignFirstResponder];

}
- (IBAction)btnUAcount:(id)sender
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,     NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:@"contacts.db"];
FMDatabase *database = [FMDatabase databaseWithPath:path];

if ([txtUname.text length] == 0 ||
    [txtPass.text length]== 0   ||
    [txtEmail.text length]== 0  ||
    [txtNumber.text length]== 0)
{
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Error" message:@"Kindly     enter details in all fields" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];

}
else

{
    if ([database open])
    {

        [database executeUpdate:@"insert into RegMembers(username, password, email,     number) values(?,?,?,?)",
        [NSString stringWithFormat: @"%@",txtUname.text],[NSString     stringWithFormat:@"%@",txtPass.text],[NSString stringWithFormat:@"%@",txtEmail.text],    [NSString stringWithFormat:@"%@",txtNumber.text],nil];
        if (1)
        {
            NSLog(@"contact added");
            self.txtUname.text = @"";
            self.txtPass.text = @"";
            self.txtEmail.text = @"";
            self.txtNumber.text = @"";
        }
        else
        {
            NSLog(@"failed to add contact");
        }

    }
    [database close];
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Registeration succesful"     message:@"Thanks for choosing edmunds" delegate:nil cancelButtonTitle:@"OK"     otherButtonTitles: nil];
    [alert show];
    [self.navigationController popViewControllerAnimated:YES];


}
Was it helpful?

Solution

If you want to check to see if the userid/password combination is in your database, you can:

#import "FMDatabaseAdditions"

and then you can see if the userid/password combination qualifies as a successful login like so:

BOOL success = NO;

NSInteger count = [database intForQuery:@"select count(*) from RegMembers where USERNAME = ? and PASSWORD = ?", username, password];

if (count > 0)
    success = YES;

Having said that, I have a couple of observations ranging from the trivial to the critical:

  1. Right now you're always reporting "contact added". You should really determine whether the insert succeeded or not. You can do this by checking the value returned by the executeUpdate method (returns YES if successful, NO if the INSERT failed).

  2. When using a PRIMARY KEY AUTOINCREMENT key, you should not use DEFAULT 0. First, I don't think that accomplishes anything (it will start at 1, regardless). Second, even if it did, it would be very bad to use zero because FMDB's lastInsertRowId, which calls SQLite sqlite3_last_insert_rowid, uses zero value for the numeric key to designate an error. So, never use zero.

  3. Far more critical, you should never store passwords on the device unencrypted. (Even if you don't care about the security of your app, too many users re-use passwords, so you want to make sure that you don't become a possible way for their password to be compromised.)

    At the very least, you'd want to encrypt the password when you store it in the database, and then, when logging in, encrypt the password that the user provided, and compare the two encrypted passwords. If you want to see some of the cryptographic services available, see the Cryptographic Services Guide.

  4. Having said that, you might not even want to write any password encryption code yourself (to do this properly is not entirely trivial).

    Using the iOS Keychain is probably better. Apple's primer on the topic is the WWDC 2013 video Protecting Secrets with the Keychain.

    For example, to save the password, email address, and number associated with a userid, you could do something like:

    // see if the userid already exists
    
    NSDictionary* query = @{(__bridge id)kSecClass       : (__bridge id)kSecClassGenericPassword,
                            (__bridge id)kSecAttrService : @"com.domain.app",
                            (__bridge id)kSecAttrAccount : self.useridTextField.text,
                            (__bridge id)kSecMatchLimit  : (__bridge id)kSecMatchLimitOne,
                            (__bridge id)kSecReturnData  : @NO};
    
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL);
    
    if (status == errSecSuccess)
    {
        [[[UIAlertView alloc] initWithTitle:nil message:@"That userid is already registered" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
        return;
    }
    
    // create payload of secret data
    
    NSDictionary *secret = @{@"password" : self.passwordTextField.text ?: [NSNull null],
                             @"email"    : self.emailTextField.text    ?: [NSNull null],
                             @"number"   : self.numberTextField.text   ?: [NSNull null]};
    
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:secret];
    
    // create keychain query
    
    query = @{(__bridge id)kSecClass       : (__bridge id)kSecClassGenericPassword,
              (__bridge id)kSecAttrService : @"com.domain.app",
              (__bridge id)kSecAttrAccount : self.useridTextField.text,
              (__bridge id)kSecValueData   : data};
    
    // add data associated with the userid in the keychain
    
    status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
    NSAssert(status == errSecSuccess, @"%s: SecItemAdd error: %lu", __FUNCTION__, (unsigned long)status);
    

    Then, when you want to log in, you can do something like:

    BOOL success = NO;
    
    NSDictionary* query = @{(__bridge id)kSecClass       : (__bridge id)kSecClassGenericPassword,
                            (__bridge id)kSecAttrService : @"com.domain.app",
                            (__bridge id)kSecAttrAccount : self.useridTextField.text,
                            (__bridge id)kSecMatchLimit  : (__bridge id)kSecMatchLimitOne,
                            (__bridge id)kSecReturnData  : @YES};
    
    CFTypeRef typeRef;
    
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &typeRef);
    
    // if we found keychain entry for that userid, check the password
    
    if (status == noErr)
    {
        NSDictionary *dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)typeRef];
        NSAssert(dictionary, @"%s: unarchiveObjectWithData failed: %@", __FUNCTION__, (__bridge NSData *)typeRef);
        NSString *password = dictionary[@"password"];
        if ([self.passwordTextField.text isEqualToString:password])
            success = YES;
    
        CFRelease(typeRef);
    }
    
    // if we didn't succeed for any reason, tell the user
    
    if (!success)
    {
        [[[UIAlertView alloc] initWithTitle:nil message:@"Login failed" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show];
    }
    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top