iOS 数据存储(三) -持久化 keychain

程序员 2024-9-19 20:49:12 83 0 来自 中国
一、简介

keychain 是一个相对独立的空间,生存到 keychain钥匙串中的信息不会由于卸载/重装 app 而丢失, 。相对于 NSUserDefaults、plist 文件生存等一样寻常方式,keychain 生存更为安全。以是我们会用 keyChain 生存一些私密信息,好比暗码、证书、装备唯一码(把获取到用户装备的唯一I D 存到 keychain 内里如许卸载或重装之后还可以获取到 id,包管了一个装备一个ID)等等。keychain 是用 SQLite 举行存储的。用苹果的话来说是一个专业的数据库,加密我们生存的数据,可以通过 metadata(attributes) 举行高效的搜刮。keychain 得当生存一些比力小的数据量的数据,如果要生存大的数据,可以考虑文件的情势存储在磁盘上,在keychain内里生存解密这个文件的密钥。
二、使用

keychain 的使用雷同于数据库,以是也有相应的增编削查操纵的语句。
必要导入 Security 库引入头文件 #import <Security/Security.h>
#import "ViewController.h"#import <Security/Security.h>@interface ViewController ()@end@implementation ViewControllerNSString *const accessItem = @"XXXXXXX.com.miongpao.KeyChainDemo";- (void)viewDidLoad {    [super viewDidLoad];    self.view.backgroundColor = [UIColor whiteColor];}- (NSMutableDictionary *)getKeychainQueryNSString *)service {    return [NSMutableDictionary dictionaryWithObjectsAndKeysid)kSecClassGenericPassword,(id)kSecClass,service, (id)kSecAttrService,service, (id)kSecAttrAccount,(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,nil];}/** 增加 */- (void)addKeychainDataid)data forKeyNSString *)key{    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];    SecItemDelete((__bridge CFDictionaryRef)keychainQuery);    [keychainQuery setObject:accessItem forKeyid)kSecAttrAccessGroup];    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey__bridge id)kSecValueData];    SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);}/** 删除 */- (void)deleteWithServiceNSString *)service {    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];    SecItemDelete((CFDictionaryRef)keychainQuery);}/** 修改 */-(void)updateKeychainDataid)data forKeyNSString *)key {    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];    [keychainQuery setObject:accessItem forKeyid)kSecAttrAccessGroup];    NSData * updata = [NSKeyedArchiver archivedDataWithRootObject:data];    NSDictionary *myDate = @{(__bridge id)kSecValueData : updata};    SecItemUpdate((__bridge CFDictionaryRef)keychainQuery, (__bridge CFDictionaryRef)myDate);}/** 查询 */- (id)readForkey:(NSString *)key {    id ret = nil;    NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];    [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:(__bridge NSData *)keyData];        } @catch (NSException *e) {            NSLog(@"Unarchive of %@ failed: %@", key, e);        } @finally {        }    }    if (keyData)CFRelease(keyData);    return ret;}@endkeychain 是一个布局,有很多key-value:
1.key - kSecClass

value阐明kSecClassGenericPassword一样寻常暗码kSecClassInternetPassword网络暗码kSecClassCertificate证书kSecClassKey密钥kSecClassIdentity身份证书(带私钥的证书)2. kSecClassGenericPassword包含的 key

key阐明范例kSecAttrCreationDate创建日期CFDateRefkSecAttrModificationDate末了一次修改日期CFDateRefkSecAttrDescription形貌CFStringRefkSecAttrComment解释CFStringRefkSecAttrCreator创建者CFNumberRef(4字符,如'aLXY')kSecAttrType范例CFNumberRef(4字符,如'aTyp')kSecAttrLabel标签(给用户看)CFStringRefkSecAttrIsInvisible是否隐蔽CFBooleanRef(kCFBooleanTrue,kCFBooleanFalse)kSecAttrIsNegative是否具有暗码,此项表示当前的 item 是否只是一个占位项,大概说是只有 key 没有 valueCFBooleanRef(kCFBooleanTrue,kCFBooleanFalse)kSecAttrAccount账户名CFStringRefkSecAttrService所具有服务CFStringRefkSecAttrGeneric用户自界说内容CFDataRefkSecAttrSecurityDomain网络安全域CFStringRefkSecAttrServer服务器域名或IP地点CFStringRefkSecAttrAccessible可访问性范例透明.3.key - kSecAttrAccessible

这个属性,决定了我们 item 在什么条件下可以获取到内里的内容,我们在添加 item 的时间,可以添加这个属性,来加强数据的安全性,具体的重要有以下几个:
value阐明kSecAttrAccessibleWhenUnlocked解锁可访问,备份kSecAttrAccessibleAfterFirstUnlock第一次解锁后可访问,备份kSecAttrAccessibleAlways不停可访问,备份kSecAttrAccessibleWhenUnlockedThisDeviceOnly解锁可访问,不备份kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly第一次解锁后可访问,不备份kSecAttrAccessibleAlwaysThisDeviceOnly不停可访问,不备份每个意思都很明白,item 默认就是 kSecAttrAccessibleWhenUnlocked,也就是在装备未锁屏的环境下。这个也是苹果保举的。kSecAttrAccessibleAlways 这个苹果在 WWDC 中也说了,不发起使用,苹果本身已经都弃用了。kSecAttrAccessibleAfterFirstUnlock 这个是在装备第一次解锁后,可以使用。这个最常见的就是配景唤醒功能内里,如果必要访问某个 item,那么必要使用这个属性,否则是访问不了 item 的数据的。末了几个 DeviceOnly 干系的设置,如果设置了,那么在手机备份规复到其他装备时,是不能被规复的。同样 iCloud 也不会同步到其他装备,由于在其他装备上是解密不出来的。
三、数据共享

同一个开辟者账号下(teamID),各个应用之间可以共享 item。keychain 通过 keychain-access-groups
来举行访问权限的控制。在 Xcode 的 Capabilities 选项中打开 Keychain Sharing 即可。
    //添加    NSDictionary *query = @{(__bridge id)kSecAttrAccessible : (__bridge id)kSecAttrAccessibleWhenUnlocked,                                (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,                                (__bridge id)kSecValueData : [@"1234562" dataUsingEncoding:NSUTF8StringEncoding],                                (__bridge id)kSecAttrAccount : @"account name",                                (__bridge id)kSecAttrAccessGroup : @"XEGH3759AB.com.developer.test",                                (__bridge id)kSecAttrService : @"noraml1",                                (__bridge id)kSecAttrSynchronizable : @YES,                                };            CFErrorRef error = NULL;    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);        //读取    NSDictionary *query1 = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,                                (__bridge id)kSecReturnRef : @YES,                                (__bridge id)kSecReturnData : @YES,                                (__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitAll,                                (__bridge id)kSecAttrAccount : @"account name",                                (__bridge id)kSecAttrAccessGroup : @"XEGH3759AB.com.developer.test",                                (__bridge id)kSecAttrService : @"noraml1",                                };            CFTypeRef dataTypeRef = NULL;    OSStatus status1 = SecItemCopyMatching((__bridge CFDictionaryRef)query1, &dataTypeRef)    //只必要添加一个kSecAttrAccessGroup属性即可。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-12-4 16:29, Processed in 0.147808 second(s), 33 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表