How to use fmdb for a login page?

前端 未结 1 1165
耶瑟儿~
耶瑟儿~ 2021-01-25 02:33

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

相关标签:
1条回答
  • 2021-01-25 03:15

    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];
      }
      
    0 讨论(0)
提交回复
热议问题