iOS Keychain钥匙串,应用间数据共享打造iOS上的全家桶
Demo先行:https://github.com/rayshen/GIKeychainGroupDemo
该demo里有2个工程,你先运行任何一个会存储一个值,再运行另一个会访问之前的app存储的值,并修改。
官方:https://developer.apple.com/library/ios/samplecode/GenericKeychain/Introduction/Intro.html
之前博客使用过Keychain,实现了数据删除APP后还能保存,但是并没有实现APP间的共享。
实现APP间的数据共享,主要依赖于在数据存入钥匙串时,使用同一个钥匙串条目。
主要分为两部分:
1.赋予应用对某个钥匙串条目的访问权限。
2.写入时配置钥匙串条目,对kSecAttrAccessGroup的值进行设置。
一、APP对钥匙串的访问权限:
(1)未对应用APP的entitlement(授权)进行配置时,APP使用钥匙串存储时,会默认存储在自身BundleID的条目下。
(2)对APP的entitlement(授权)进行配置后,说明APP有了对某个条目的访问权限。
钥匙串的可视化效果可参见Mac的APP-钥匙串访问。
APP钥匙串访问权限的配置方法:(这里XXXXX模拟器随意,但真机必须为自己开发者账号ID,否则无法通过编译)
1.新建一个Plist文件,在Plist中的数组中添加可以访问的条目的名字(如KeychainAccessGroups.plist),结构如下:
Plist代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>keychain-access-groups</key>
<array>
<string>XXXXX.GrassInfoAppFamily</string>
</array>
</dict>
</plist>
2.在Build-setting中进行配置,搜索entitlement,注意路径别配置错:
二、APP对钥匙串的操作:
钥匙串的操作接口都位于Security.framework框架下,它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的。
其过程可以总结为:
1.配置查询字典,格式是NSMutableDictionary,需要配置的内容下次再分析,功能就相当于写一句SQL一样。
2.进行增(SecItemAdd)、删(SecItemDelete)、改(SecItemUpdate)、查(SecItemCopyMatching)。
代码Demo里面有,这里以增为例,下面有2个语句,一个是增加到自身BundleID的钥匙串条目,一个是增加到共享的条目中。
//创建一个基本的查询字典
+ (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)addKeychainData:(id)data forKey:(NSString *)key{
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
//Delete old item before add new item
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
} +(void)addShareKeyChainData:(id)data forKey:(NSString *)key{
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
[keychainQuery setObject:accessGroupItem forKey:(id)kSecAttrAccessGroup];
//Delete old item before add new item
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}
函数 [keychainQuery setObject:accessGroupItem forKey:(id)kSecAttrAccessGroup] 的配置,就是指定了这次写入时的钥匙串条目,不写入时默认为plist配置文件里第一个条目。
在查询中,也可以对查询的钥匙串条目进行配置,默认会对所有有权限的条目进行搜索。
三、keychain的组成:
参考博客:http://my.oschina.net/w11h22j33/blog/206713
每一个keyChain的组成如图,整体是一个字典结构.
1.kSecClass key 定义属于那一种类型的keyChain
2.不同的类型包含不同的Attributes,这些attributes定义了这个item的具体信息
3.每个item可以包含一个密码项来存储对应的密码
对于最常用密码类型,我们应该如下配置
[wrapper setObject:kSecClassGenericPassword forKey:(id)kSecClass];//class
[wrapper setObject:@"username" forKey:(id)kSecAttrAccount];//key
[wrapper setObject:@"password"forKey:(id)kSecValueData];//value
[wrapper setObject:(id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(id)kSecAttrAccessible];
kSecAttrAccessiblein变量用来指定这个应用合适需要访问这个数据。我们需要对这个选项特别注意,并且使用最严格的选项。这个键(key)可以设置6种值。
你可以参考以下:
四、安全
前面说到,APP能够访问的keychain数据是通过其entitlements文件指定的。
但是!!如果使用带有一个*通配符的entitlments,因此它能够访问keychain中的所有条目。。或者,如果用一个包含所有访问组(access group)的entitlements文件,也能够访问所有的keychain数据。
但以上仅限模拟器,在真机调试时,假如你plist里的条目,和自己调试文件(pro file)的ID不一致时(比如:EC0880A1.company),进行真机编译的时候是会报错的。
所以真正要保证全家桶,还需要保证这些APP在同一个开发者ID下才行。
前面关于在未配置keychain-access-group的情况下,我参考别人说是默认存储在该BundleID的条目下,但实测并非存储在该条目下。具体为什么我也暂时不清楚。但是可以肯定的是,在iOS的沙盒机制中,你默认存储的条目下的K-V,其他APP是无法访问的(除了模拟器中的通配符*,真机是不行的)。
关于Keychain还有很多值得挖掘的,比如具体在sqlite数据库的表单存储方式等,有错欢迎指正。
iOS Keychain钥匙串,应用间数据共享打造iOS上的全家桶的更多相关文章
- iOS keyChain(钥匙串)的简单使用
通常在开发中我们需要长久的保存某些值比如用户的账号密码等,对于隐私度很高的数据来说保证数据的安全性是尤为重要的.ios中的keyChain是一种很好的选择. 首先去开发者网站(https://deve ...
- iOS - keychain 详解及变化
keychain介绍 iOS keychain 是一个相对独立的空间,保存到keychain钥匙串中的信息不会因为卸载/重装app而丢失, .相对于NSUserDefaults.plist文件保存等一 ...
- 聊聊iOS Keychain
某天,小熊碰见这样一个错误 Couldn't update the Keychain Item问题处理 ,网上搜索了下网上很多解决方案,依然百撕不得骑姐.后来参考下面两篇文章.才发现是用法不正确,网上 ...
- iOS keyChain 的使用
详细资料,请参看苹果官方文档Keychain Services Reference . ios中的keychain,用于保存用户的机密信息,对keychain的操作有4种,就是 增,删,改,查: Se ...
- iOS编程——经过UUID和KeyChain来代替Mac地址实现iOS设备的唯一标示(OC版)
iOS编程——通过UUID和KeyChain来代替Mac地址实现iOS设备的唯一标示(OC版) 很多的应用都需要用到手机的唯一标示,而且要求这个唯一标示不能因为应用app的卸载或者改变而变化. 在iO ...
- (转)iOS Wow体验 - 第五章 - 利用iOS技术特性打造最佳体验
本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第五章译文精选,其余章节将陆续放出.上一篇:Wow ...
- [iOS Keychain本地长期键值存储]
目前本地存储方式大致有:Sqlite,Coredata,NSUserdefaults.但他们都是在删除APP后就会被删除,如果长期使用存储,可以使用Keychain钥匙串来实现. CHKeychain ...
- iOS开发技术分享(1)— iOS本地数据存储
iOS开发技术分享(1)— iOS本地数据存储 前言: 我本是一名asp.net程序员,后来加入了iOS游戏开发队伍,到现在也有一年多的时间了.这一年来,每天都干到2.3点钟才睡觉,不为别的,只为了学 ...
- 李洪强iOS之集成极光推送二iOS 证书 设置指南
李洪强iOS之集成极光推送二iOS 证书 设置指南 创建应用程序ID 登陆 iOS Dev Center 选择进入iOS Provisioning Portal. 在 iOS Provisioning ...
随机推荐
- tkinter 类继承的三种方式
tkinter class继承有三种方式. 提醒注意这几种继承的运行方式 一.继承 object 1.铺tk.Frame给parent: 说明: self.rootframe = tk.Frame(p ...
- React入门 (1)—使用指南(包括ES5和ES6对比)
前言 本篇会简明扼要的介绍一下React的使用方法.代码会用JSX+ES5和JSX+ES6两种方式实现. React简介 React来自Facebook,于2013年开源.至今不断修改完善,现在已经到 ...
- 【Flex】正则表达式
1.基本语法 . 匹配除换行符"\n"外的任意单个字符. * 匹配前面Flex正则表达式的零次或多次出现.eg:Alert.show("ThisBookIsGoodBoo ...
- 用PHP+H5+Boostrap做简单的音乐播放器(进阶版)
前言:之前做了一个音乐播放器(纯前端),意外的受欢迎,然后有人建议我把后台一起做了,正好也想学习后台,所以学了两天php(不要吐槽我的速度,慢工出细活嘛~)然后在之前的基础上也又完善了一些功能,所以这 ...
- ALinq Dynamic 使用指南——代码的获取与编译
1.下载代码 ALinq Dynamic 项目托管在 CodePlex 网站,你可以使用浏览器下载压缩包,或者通过 SVN 获取. 项目网址:http://esql.codeplex.com/ 压缩包 ...
- win8/8.1 免密码登录设置
http://www.ehow.com/how_8013338_start-windows-password.html 原文见上方链接 1,win+r调出命令输入窗口,输入 netplwiz 回车 2 ...
- CSS Bug
父子标签间用margin的问题,表现在有时除IE(6/7)外的浏览器子标签margin转移到了父标签上,IE6&7下没有转移.测试代码: <body> <style type ...
- bindService初步了解
bindService的使用: 当需要调Service里面的方法时,可以用bindService() 首先定义一个类继承于Service,然后配置Manifest.xml文件 public class ...
- Service之来电监听(失败的案例)
Service:服务,可以理解成一个运行再后台没有界面的Activity,集成于Seriver,是四大组件之一 Service的继承关系:Service-->ContextWrapper--&g ...
- 各组对final发布产品的排名
结果 排名 组名 项目简称 组长 平均 方差 1 新蜂 俄罗斯 武志远 2 0.80 2 天天向上 连连看 王森 2.50 1.90 3 奋斗吧兄弟 食物链 黄兴 2.83 0.97 4 金洲勇士 考 ...