使用KeyChain处理用户名和密码
KeyChain
本地持久化用户名和密码是常见的需求。
为什么不用NSUserDefault来保存用户名和密码呢?因为NSUserDefault可以在资料沙盒中找到。
对应的沙盒路径:
Library -> Preferences -> bundleId.plist
只要找到这个文件,储存在里面的信息便被盗取。
另外,存在KeyChain里的信息是不会随APP被删除而删除的,还可以支持iCloud同步。
api
用到的api有以下4个:
SecItemAdd(CFDictionaryRef _Nonnull attributes, CFTypeRef _Nullable * _Nullable result)
SecItemUpdate(CFDictionaryRef _Nonnull query, CFDictionaryRef _Nonnull attributesToUpdate)
SecItemCopyMatching(CFDictionaryRef _Nonnull query, CFTypeRef _Nullable * _Nullable result)
SecItemDelete(CFDictionaryRef _Nonnull query)
查询:
NSMutableDictionary *query = [NSMutableDictionary new];
[query setValue:service forKey:(__bridge id)kSecAttrService]; //标识
[query setValue:account forKey:(__bridge id)kSecAttrAccount];//账户
[query setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; //储存密码
[query setValue:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];//设置返回数据
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
增加:
NSMutableDictionary *query = [NSMutableDictionary new];
[query setValue:service forKey:(__bridge id)kSecAttrService]; //标识
[query setValue:account forKey:(__bridge id)kSecAttrAccount];//账户
[query setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; //储存密码
[query setValue:pwdData forKey:(__bridge id)kSecValueData];
status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
更新:
NSMutableDictionary *query = [NSMutableDictionary new];
[query setValue:service forKey:(__bridge id)kSecAttrService]; //标识
[query setValue:account forKey:(__bridge id)kSecAttrAccount];//账户
[query setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; //储存密码
NSMutableDictionary *newQuery = [NSMutableDictionary dictionary];
[newQuery setValue:pwdData forKey:(__bridge id)kSecValueData];
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)newQuery);
删除:
NSMutableDictionary *query = [NSMutableDictionary new];
[query setValue:service forKey:(__bridge id)kSecAttrService]; //标识
[query setValue:account forKey:(__bridge id)kSecAttrAccount];//账户
[query setValue:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; //储存密码
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);