I'm very new to iOS development so forgive me if this is a newbie question. I have a simple authentication mechanism for my app that takes a user's email address and password. I also have a switch that says 'Remember me'. If the user toggles that switch on, I'd like to preserve their email/password so those fields can be auto-populated in the future.
I've gotten this to work with saving to a plist file but I know that's not the best idea since the password is unencrypted. I found some sample code for saving to the keychain, but to be honest, I'm a little lost. For the function below, I'm not sure how to call it and how to modify it to save the email address as well.
I'm guessing to call it would be: saveString(@"passwordgoeshere");
Thank you for any help!!!
+ (void)saveString:(NSString *)inputString forKey:(NSString *)account { NSAssert(account != nil, @"Invalid account"); NSAssert(inputString != nil, @"Invalid string"); NSMutableDictionary *query = [NSMutableDictionary dictionary]; [query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; [query setObject:account forKey:(id)kSecAttrAccount]; [query setObject:(id)kSecAttrAccessibleWhenUnlocked forKey:(id)kSecAttrAccessible]; OSStatus error = SecItemCopyMatching((CFDictionaryRef)query, NULL); if (error == errSecSuccess) { // do update NSDictionary *attributesToUpdate = [NSDictionary dictionaryWithObject:[inputString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData]; error = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributesToUpdate); NSAssert1(error == errSecSuccess, @"SecItemUpdate failed: %d", error); } else if (error == errSecItemNotFound) { // do add [query setObject:[inputString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData]; error = SecItemAdd((CFDictionaryRef)query, NULL); NSAssert1(error == errSecSuccess, @"SecItemAdd failed: %d", error); } else { NSAssert1(NO, @"SecItemCopyMatching failed: %d", error); } }
Step 2: How to autofill passwords on KeychainOpen the Settings app. Scroll down and select the Passwords tab. Select the AutoFill Passwords tab. Make sure the AutoFill Passwords is toggled on (green).
With iCloud Keychain, you can keep your passwords and other secure information updated across your devices. iCloud Keychain remembers things, so that you don't have to. It auto-fills your information—like your Safari usernames and passwords, credit cards, and Wi-Fi passwords on any device that you approve.
I've written a simple wrapper that allows saving of any NSCoding-compliant object to the keychain. You could, for example, store your email and password in an NSDictionary and store the NSDictionary to the keychain using this class.
SimpleKeychain.h
#import <Foundation/Foundation.h> @class SimpleKeychainUserPass; @interface SimpleKeychain : NSObject + (void)save:(NSString *)service data:(id)data; + (id)load:(NSString *)service; + (void)delete:(NSString *)service; @end
SimpleKeychain.m
#import "SimpleKeychain.h" @implementation SimpleKeychain + (NSMutableDictionary *)getKeychainQuery:(NSString *)service { return [NSMutableDictionary dictionaryWithObjectsAndKeys: (id)kSecClassGenericPassword, (id)kSecClass, service, (id)kSecAttrService, service, (id)kSecAttrAccount, (id)kSecAttrAccessibleAfterFirstUnlock, (id)kSecAttrAccessible, nil]; } + (void)save:(NSString *)service data:(id)data { NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; SecItemDelete((CFDictionaryRef)keychainQuery); [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData]; SecItemAdd((CFDictionaryRef)keychainQuery, NULL); } + (id)load:(NSString *)service { id ret = nil; NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; CFDataRef keyData = NULL; if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { @try { ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData]; } @catch (NSException *e) { NSLog(@"Unarchive of %@ failed: %@", service, e); } @finally {} } if (keyData) CFRelease(keyData); return ret; } + (void)delete:(NSString *)service { NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; SecItemDelete((CFDictionaryRef)keychainQuery); } @end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With