2011-03-09 142 views
56

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

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

我猜打电话给那就是: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); 
    } 
} 
+5

我固定@失范的代码与ARC工作,并把它在Github上(我链接到这个答案,并在这两个文件中提到你的用户,但如果你想了解更多的归因,请让我知道)。我也改变了一些格式,使得方法名称更通用一些。 https://github.com/jeremangnr/JNKeychain – jere 2013-05-13 15:37:22

回答

100

我写了一个简单的包装,允许任何符合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 
+0

这会为osx keycahin工作吗? – abe 2011-07-06 19:12:31

+0

@abe:试试看看?根据文档,所有相同的函数都可用,但是'getKeychainQuery:'可能需要在字典中有额外的参数。 – Anomie 2011-07-07 01:52:51

+0

@Anomie我试了一下,发现它的错误值,其中之一是kSecClassGenericPassword,但我检查了文档,它似乎是在基础框架的支持,我还包括安全框架的任何想法,它可能会出错? thx – abe 2011-07-07 06:10:29

38

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 
+3

感谢您使用ARC准备好版本。它像一个魅力。 – 2013-12-07 05:34:30

+0

不是问题:) – 2013-12-07 08:56:49

+0

完美无缺,thx! – mnl 2014-07-21 12:59:06

相关问题