将电子邮件/密码保存到iOS中的钥匙串

我对iOS开发很陌生,所以如果这是一个新手问题,请原谅我。 我有一个简单的身份validation机制来接收用户的电子邮件地址和密码。 我也有一个开关说“记住我”。 如果用户切换开关,我想保留他们的电子邮件/密码,以便将来这些字段可以自动填充。

我已经得到这个保存到plist文件的工作,但我知道这不是最好的主意,因为密码是未encryption的。 我发现一些示例代码保存到钥匙串,但说实话,我有点失落。 对于下面的function,我不知道如何调用它,以及如何修改它以保存电子邮件地址。

我猜想调用它会是: saveString(@"passwordgoeshere");

感谢您的任何帮助!!!

 + (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); } } 

我写了一个简单的包装,允许任何符合NSCoding的对象保存到钥匙串。 例如,您可以将您的电子邮件和密码存储在NSDictionary中,并使用此类将NSDictionary存储到钥匙串中。

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 

ARC准备好的代码:

KeychainUserPass.h

 #import <Foundation/Foundation.h> @interface KeychainUserPass : NSObject + (void)save:(NSString *)service data:(id)data; + (id)load:(NSString *)service; + (void)delete:(NSString *)service; @end 

KeychainUserPass.m

 #import "KeychainUserPass.h" @implementation KeychainUserPass + (NSMutableDictionary *)getKeychainQuery:(NSString *)service { return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass, service, (__bridge id)kSecAttrService, service, (__bridge id)kSecAttrAccount, (__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrAccessible, nil]; } + (void)save:(NSString *)service data:(id)data { NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; SecItemDelete((__bridge CFDictionaryRef)keychainQuery); [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData]; SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL); } + (id)load:(NSString *)service { id ret = nil; NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; [keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; CFDataRef keyData = NULL; if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { @try { ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge 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((__bridge CFDictionaryRef)keychainQuery); } @end