Saving Email/Password to Keychain in iOS

后端 未结 2 1337
鱼传尺愫
鱼传尺愫 2020-11-28 01:16

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 pass

相关标签:
2条回答
  • 2020-11-28 01:26

    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
    
    0 讨论(0)
  • 2020-11-28 01:36

    ARC ready code:

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