iOS keychain 主要是用来保存一些用户敏感数据。比如用户密码,token。keychain是用SQLite进行存储的。用苹果的话来说是一个专业的数据库,加密我们保存的数据,可以通过metadata(attributes)进行高效的搜索。keychain适合保存一些比较小的数据量的数据,如果要保存大的数据,可以考虑文件的形式存储在磁盘上,在keychain里面保存解密这个文件的密钥。

keychain的类型

kSecClassGenericPassword

kSecClassInternetPassword

kSecClassCertificate

kSecClassKey

kSecClassIdentity

这5个类型只是对应于不同的item,存储的属性有区别,使用上都是一样的。

不同类型对应的属性:

14658371868385.jpg

既然苹果是采用SQLite去存储的,那么以上这些不同item的attribute可以理解是数据库里面表的字段。那么对keychain的操作其实也就是普通数据库的增删改查了。这样也许就会觉得那些API也没那么难用了。

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)kSecAttrService : @"loginPassword",

};

CFErrorRef error = NULL;

OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);

以这个添加kSecClassGenericPassword item为例,在字典里面我们设置了以下几个属性:获取权限为当设备处于未锁屏状态,item的类型为kSecClassGenericPassword,item的value为@"123456", item的账户名为@"account name", item的service为@"loginPassword"。最后,调用SecItemAdd进行插入。使用上有点像CoreData。

NSDictionary *query = @{

(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,

(__bridge id)kSecAttrService : @"loginPassword",

(__bridge id)kSecAttrAccount : @"account name"

};

OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query);

删除同样也是指定之前存的item的属性,最后调用SecItemDelete这个方法。这边要注意的是劲量用多个字段确定这个item,(虽然平常开发都可能是唯一)防止删除了其他item;比如我们把kSecAttrAccount这个属性去掉,那么将会删除所有的kSecAttrService对应value为@"loginPassword"的item;

NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,

(__bridge id)kSecAttrAccount : @"account name",

(__bridge id)kSecAttrService : @"loginPassword",

};

NSDictionary *update = @{

(__bridge id)kSecValueData : [@"654321" dataUsingEncoding:NSUTF8StringEncoding],

};

OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);

苹果推荐我们用SecItemUpdate去修改一个已经存在的item,可能我们喜欢先调用SecItemDelete方法去删除,再添加一个新的。这个主要目的是防止新添的item丢失了原来的部分属性。这个方法需要两个入参,一个字典是用来指定要更新的item,另一个字典是想要更新的某个属性的value,最后调用SecItemUpdate。

NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,

(__bridge id)kSecReturnData : @YES,

(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitOne,

(__bridge id)kSecAttrAccount : @"account name",

(__bridge id)kSecAttrService : @"loginPassword",

};

CFTypeRef dataTypeRef = NULL;

OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);

if (status == errSecSuccess) {

NSString *pwd = [[NSString alloc] initWithData:(__bridge NSData * _Nonnull)(dataTypeRef) encoding:NSUTF8StringEncoding];

NSLog(@"==result:%@", pwd);

}

查和前面几个操作类似,首先同样是指定属性定位到这个item,最后调用SecItemCopyMatching方法。既然是数据库查询,肯定会有记录的条数的问题。本例中使用了kSecMatchLimitOne,表示返回结果集的第一个,当然这个也是默认的。如果是查询出多个,kSecMatchLimitAll可以使用这个,那么返回的将是个数组。SecItemCopyMatching方法的入参dataTypeRef,是一个返回结果的引用,会根据不同的item,返回对应不同的类型(如NSCFData, NSCFDictionary, NSCFArray等等)。

刚刚上面是返回存储的value的引用,如果我们想看看这个item所有的属性怎么办?我们可以使用kSecReturnRef

NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,

(__bridge id)kSecReturnRef : @YES,

(__bridge id)kSecReturnData : @YES,

(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitOne,

(__bridge id)kSecAttrAccount : @"account name",

(__bridge id)kSecAttrService : @"noraml",

};

CFTypeRef dataTypeRef = NULL;

OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);

if (status == errSecSuccess) {

NSDictionary *dict = (__bridge NSDictionary *)dataTypeRef;

NSString *acccount = dict[(id)kSecAttrAccount];

NSData *data = dict[(id)kSecValueData];

NSString *pwd = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSString *service = dict[(id)kSecAttrService];

NSLog(@"==result:%@", dict);

}

这样,我们就得到了这个item的所有属性。

Sharing Items

通一个开发者账号下,各个应用之间可以共享item。keychain通过keychain-access-groups

来进行访问权限的控制。在Xcode的Capabilities选项中打开Keychain Sharing即可。

每个group命名开头必须是开发者账号的teamId。不同开发者账号的teamId是唯一的,所以苹果限制了只有同一个开发者账号下的应用才可以进行共享。如果有多个sharedGroup,在添加的时候如果不指定,默认是第一个group。

添加:

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 *query = @{(__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 status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);

只需要添加一个kSecAttrAccessGroup属性即可。

安卓设置keychain_keychain(一)相关推荐

  1. 安卓设置keychain_Keychain的使用

    之前做项目,用户保存账号密码都会保存到NSUserdefault中,每次卸载了app后,数据都会随之清除,而且不安全.后来系统就提供了keychain作为存储账号,密码,网络密码,认证令牌的工具,然后 ...

  2. 安卓设置均衡器 Equalizer

    前言 工作与音乐相关的,所以避免不了工作中要涉及到 Equalizer .中文叫均衡器,缩写就是 EQ,和情商的缩写一样.我先抛砖引玉,说直白点就是把声音优化来更好听.我直接搬移一段维基百科的说明,这 ...

  3. 巡线机器人 - PID控制 - 安卓设置

    巡线机器人 - PID控制 - 安卓设置 原文 该项目的目的是构建具有PID控制的巡线机器人.我们还将使用Android设备轻松设置主要控制参数,以便更好,更快地进行调谐.项目中用到的舵机也可用MG9 ...

  4. 【UE4(虚幻)】学习笔记(七)---- UE4安卓打包整理及安卓设置常用设置说明

    本次学习笔记分为两个部分: 1.整理UE4打包教程 2.补充说明打包中细节 一.整理UE4打包教程 哔哩哔哩 哔哩哔哩 上面两个视频参照着来理解打包,android配置文件建议下载一直闪光皮皮虾那个u ...

  5. 安卓设置Activity切换动画无效的问题

    做安卓App时,常会设置Activity之间切换的动画.常用的方法有两种,一种是用Activity的overridePendingTransition方法:另一种是用style文件通过xml进行设置. ...

  6. 安卓设置原生alert设置圆角_安卓手机设置充电提示音全新最全教程

    安卓版充电提示音教程_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​m.bilibili.com 哎,自从前端时间IOS14发布后,他的其他所有功能没有活,唯一火了充电提示音.奈何大傻没有苹果手 ...

  7. 安卓设置原生alert设置圆角_每个月流量都超额?安卓、苹果用户可以尝试更改这些设置...

    虽然目前三大运营商均针对手机流量的使用情况推出了专属的流量卡以及大流量套餐,但是相信不少用户每个月还是要缴纳一笔不小的流量费用,部分用户甚至出现了刚给手机充值完话费就出现余额不足的情况.其实出现这些情 ...

  8. 安卓设置菊花动画_华为手机必须调整的4个默认设置,让手机流畅到飞起,用到2035年...

    安卓手机用久了,难免都会出现卡顿的问题.这个问题一直困扰着大家,很多人每隔一两年就要换手机,真的太亏了.今天我们就以华为手机为例,讲一讲有什么办法,能解决手机卡顿的问题,希望对你们有帮助. 一.开发者 ...

  9. 安卓设置字符串样式,字符串中部分字体样式

    引言: 最近,我遇到一个问题,要显示一行字符串,但是要求部分的样式与整体不同.我以前实现这种操作的方法是用多个TextView分别设置样式.但是,今天我发现对于一些简单的样式设定,其实只用一个Text ...

最新文章

  1. 元宇宙新地王2740万元刷爆纪录!虚拟炒房一周成交6.37亿
  2. excel转成csv格式的默认分隔符
  3. 「offer来了」保姆级巩固你的js知识体系(4.0w字)
  4. 基于8086CPU微处理器的汇编学习之JMP指令
  5. 添加ejs后页面空白解决办法
  6. CSS 元素超出部分滚动, 并隐藏滚动条
  7. localStorage、cookie
  8. CentOS7 下安装telnet服务
  9. ACR122U写卡软件v3.6绿色版
  10. 为了机器学习把MacBook Pro换成Asus TUF Gaming 全家桶
  11. 异步FIFO设计与实现及相关问题
  12. 手机html编辑器微信,135微信(135编辑器手机版网页版)
  13. 骚操作:Mac局域网控制Windows10主机
  14. JS特效一:图片轮播图(JS必须掌握的特效)
  15. Android 实现 iBeacon
  16. linux系统设置开机启动,linux下设置自己的程序开机自启动
  17. 【c】c语言中逗号运算符和逗号表达式
  18. 损失函数,mse,cee
  19. 耗时十年!精心整理的Java高级开发需要的分布式技术
  20. Pandas的常用操作(一)

热门文章

  1. 中国超级计算机使用率,中国天河一号超级计算机已饱和运行 使用率超过欧美...
  2. 实时操作系统μcos-III移植
  3. 多wan口路由虚拟服务器,简单的多WAN路由器带宽聚合功能测试方案
  4. linux4.1内核配置以及编译及千兆网卡dp83867网卡驱动移植
  5. 默认网关、DNS、DHCP
  6. OC10-Block
  7. 使用任务计划实现宽带pppoe断线自动连接 - Windows
  8. 低压差线性稳压器简介
  9. 第13章 Kotlin 集成 SpringBoot 服务端开发(2)
  10. 关于业财税一体化的思考