数据缓存——Keychain的使用

本文介绍了iOS中的Keychain服务,一种用于安全存储私密信息如密码和证书的机制。Keychain数据在App卸载后仍能保留,重新安装时依然有效,同时也支持应用间的数据共享。文中提到了使用苹果官方的KeychainItemWrapper和第三方库SSKeychain进行操作,并提供了操作步骤和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Keychain的使用

Demo下载地址


iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储。

用于储存一些私密信息,比如密码、证书等等,Keychain里保存的信息不会因App被删除而丢失,在用户重新安装App后依然有效。

同样也适用于应用之间数据共享。我们可以把KeyChain理解为一个Dictionary,所有数据都以key-value的形式存储,可以对这个Dictionary进行add、update、get、delete这四个操作。

 

使用苹果官方发布的KeychainItemWrapper或者SFHFKeychainUtils很方便。

或使用第三方Keychain框架:https://github.com/samsoffes/sskeychain。

 

使用

1、需要导入框架Security.framework


2、需要添加头文件 #import<Security/Security.h>


3、iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:

查询:OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef*result);

添加:OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);

更新:KeyChain中的ItemOSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRefattributesToUpdate);

删除:KeyChain中的ItemOSStatus SecItemDelete(CFDictionaryRef query)

 

位置查看:

使用Keychain-Dumper导出keychain数据

https://github.com/ptoomey3/Keychain-Dumper

操作步骤极其简单:

1)赋予Keychain数据库可读权限

Primer:~ root

# cd /private/var/Keychains/

 

Primer:/private/var/Keychains root

# ls

TrustStore.sqlite3  accountStatus.plist  caissuercache.sqlite3  keychain-2.db keychain-2.db-shm keychain-2.db-wal ocspcache.sqlite3 ocspcache.sqlite3-shm ocspcache.sqlite3-wal

 

Primer:/private/var/Keychains root

# chmod +r keychain-2.db

2)使用Keychain-Dumper导出Keychain

Primer:/private/var/Keychains root

# /your_path/keychain_dumper >keychain-export.txt

然后拷贝到本地查看,到底iOS系统和第三方应用都存放了哪些信息,就一览无余了。

 

 

代码示例:

(1)系统原生

/********************************************************************/
 
+(void)saveValue:(NSString *)value key:(NSString *)key
{
    if ((value && 0 != value.length)&& (key && 0 != key.length))
    {
        NSMutableDictionary *dict =(NSMutableDictionary *)[self load:keyChainSave];
        if (dict == nil)
        {
            dict = [NSMutableDictionarydictionary];
        }
        [dict setObject:value forKey:key];
        [self save:keyChainSave data:dict];
    }
}
 
+ (NSString*)getValueWithKey:(NSString *)key
{
    if (key && 0 != key.length)
    {
        NSMutableDictionary *dict = (NSMutableDictionary*)[self load:keyChainSave];
        NSString *value = [dictobjectForKey:key];
        return value;
    }
   
    return nil;
}
 
+(void)deleteValueWithKey:(NSString *)key
{
    if (key && 0 != key.length)
    {
        NSMutableDictionary *dict =(NSMutableDictionary *)[self load:keyChainSave];
        [dict removeObjectForKey:key];
        [self save:keyChainSave data:dict];
    }
}
 
+(void)deleteValue
{
    [self delete:keyChainSave];
}
 
/********************************************************************/
 
+(NSMutableDictionary *)getKeychainQuery:(NSString *)service
{
    return [NSMutableDictionarydictionaryWithObjectsAndKeys:
            (__bridge_transferid)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
            service, (__bridge_transferid)kSecAttrService,
            service, (__bridge_transferid)kSecAttrAccount,
            (__bridge_transferid)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
            nil];
}
 
+(void)save:(NSString *)service data:(id)data
{
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [selfgetKeychainQuery:service];
    //Delete old item before add new item
    SecItemDelete((__bridge_retainedCFDictionaryRef)keychainQuery);
    //Add new object to searchdictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiverarchivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
    //Add item to keychain with the searchdictionary
    SecItemAdd((__bridge_retainedCFDictionaryRef)keychainQuery, NULL);
}
 
+(id)load:(NSString *)service
{
    id ret = nil;
    NSMutableDictionary *keychainQuery = [selfgetKeychainQuery:service];
    //Configure the search setting
    [keychainQuery setObject:(id)kCFBooleanTrueforKey:(__bridge_transfer id)kSecReturnData];
    [keychainQuery setObject:(__bridge_transferid)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((__bridge_retainedCFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr)
    {
        @try
        {
            ret = [NSKeyedUnarchiverunarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
        }
        @catch (NSException *e)
        {
            NSLog(@"Unarchive of %@failed: %@", service, e);
        }
        @finally
        {
           
        }
    }
    return ret;
}
 
+(void)delete:(NSString *)service
{
    NSMutableDictionary *keychainQuery = [selfgetKeychainQuery:service];
    SecItemDelete((__bridge_retainedCFDictionaryRef)keychainQuery);
}
 
/********************************************************************/


(2)第三方框架SSKeychain





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

番薯大佬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值