IOS在钥匙串里保存APP的账号密码
来源:互联网 发布:淘宝黑客 编辑:程序博客网 时间:2024/04/19 00:33
用原生的 Security.framework 就可以实现钥匙串的访问、读写。但是只能在真机上进行,模拟器会出错。在 Github 上有个封装的非常好的类来实现这个功能,让你既能在模拟器又能在真机上访问钥匙串。
具体代码:
//获取密码
+ (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;
//保存密码
+ (void) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error;
//删除密码
+ (void) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;
使用方法如下:
1、引入Security.framework框架。
2、引入头文件:#import"SFHFKeychainUtils.h"
3、存密码:
- NSString *SERVICE_NAME=@"demo";
- [SFHFKeychainUtils storeUsername:@"dd"
- andPassword:@"aa"
- forServiceName:SERVICE_NAME
- updateExisting:1
- error:nil];
4、取密码:
- NSString *passWord = [SFHFKeychainUtils getPasswordForUsername:@"dd"
- andServiceName:SERVICE_NAME
- error:nil];
- NSLog(@"%@",passWord);
5、删除用户:
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在钥匙串里保存APP的账号密码
- iOS 用keychain钥匙串保存账号、设备UUID及APP间共享
- 利用钥匙串,在应用里保存用户密码的方法
- ios 利用钥匙串保存密码和获取密码
- IOS 用keychain(钥匙串)保存用户名和密码
- IOS 用keychain(钥匙串)保存用户名和密码
- IOS中使用sskeychain调用keychain(钥匙串)保存密码
- IOS 用keychain(钥匙串)保存用户名和密码
- ios上保存密码或ID的钥匙串功能实现
- iOS保存密码之钥匙串操作以及UDID设备唯一标识符获取的替代方法
- 利用钥匙串,在应用里保存用户密码的方法 转自:hager的博客
- iOS如何将APP的信息保存到沙盒之外(钥匙串中)
- 在ios开发中,使用钥匙来保存用户密码和账号
- [ios2] 利用钥匙串,在应用里保存用户密码的方法 【转】
- 钥匙串 keyChain 存储账号密码
- iOS 钥匙串保存UUID
- 钥匙串的使用——使用钥匙串进行保存本地密码
- iOS利用钥匙串保存获取设备的唯一标识
- Android复习二——第一个Android应用
- 收藏网址
- 帝国cms添加栏目前台显示正常,后台管理栏目中不显示
- hdu 1003 Max Sum(简单dp)
- BootStrap 标签页
- IOS在钥匙串里保存APP的账号密码
- 生成设备节点
- SDUT1130数据结构上机测试1:顺序表的应用(上一个代码太蠢)
- leetcode 376. Wiggle Subsequence
- Error running app: This version of Android Studio is incompatible with the Gradle Plugin used. Try d
- 评价UML工具
- linux命令提示符显示当前完整路径
- 线程安全与共享资源
- DOM对象模型高级编程(增查)