How to use fmdb for a login page?

你离开我真会死。 提交于 2019-12-02 07:02:58

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];
    }
    
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!