首页 文章

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

提问于
浏览
56

我对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);
    }
}

2 回答

  • 39

    我编写了一个简单的包装器,允许将任何符合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
    
  • 100

    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
    

相关问题