https://www.cnblogs.com/m4abcd/p/5242254.html

Keychain 使用? ---为了实用最大化我觉得我应该直接先说使用!

当然是使用第三方库啦:sskeychain 3000+星星的库不开玩笑。github地址:https://github.com/soffes/sskeychain

导入完之后首先,编译一下有无错。

如果是自己手动导入:

1.把SSKeychain.h SSKeychain.m SSKeychainQuery.h SSKeychainQuery.m 复制到工程

2.添加Security.framework 怎么添加?点一下那个+

3.SSKeychain.h有错?把SSKeychain.h 中的#import <SSKeychain/SSKeychainQuery.h> 换成 #import <Foundation/Foundation.h> #import "SSKeychainQuery.h" 吧。

还有错?作为小白我的也不知道了,发我邮件一起讨论吧。

接下来演示4个过程

基本说明:储存的数据有三个 1.服务名(这个方便对账号密码进行分类)2.账号3.密码 而这三个数据都是NSString (如果要存其他类型呢,请看后面吧)

所用到的API :

添加和更新都用这个: + (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account ;

查询密码:+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;

删除:+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;

1.添加一条钥匙    (这个钥匙的信息 由 服务名+账号+密码 组成)

记得添加头文件

#import "SSKeychain.h"

#import "SSKeychainQuery.h"

//先定义一下要用的东东

NSString *serviceName= @"com.keychaintest.data";

NSString *account = @"m4abcd";

NSString *password = @"12345678";

//加入钥匙串!

if ([SSKeychain setPassword:password forService:serviceName account:account]) {

NSLog(@"success !");

}

说明:就是这么简单咯。

2.查询

1.查询某service 下 count 的密码并且打印出来:

  NSLog(@"%@",[SSKeychain passwordForService:serviceName account:account]);

2.查询service下所有钥匙:

NSArray *keys = [SSKeychain accountsForService:serviceName];

这是我的输出:

2016-03-04 15:08:43.785 keychaintest[31342:4403403] (

        {

        acct = m4abcd;

        agrp = test;

        cdat = "2016-03-03 07:10:58 +0000";

        mdat = "2016-03-04 07:08:43 +0000";

        pdmn = ak;

        svce = "com.keychaintest.data";

        sync = 0;

        tomb = 0;

    }

)

说明:返回的结果为数组,数组成员就是我们查询的钥匙,这里只有一个钥匙,而钥匙信息以字典的形式构建的,键acct 就是count,键svce 就是serviceName。密码在哪里?用方法1去取吧骚年!

3.查询本appkeychain的所有钥匙

  NSArray *keys = [SSKeychain allAccounts];

3.更新

if([SSKeychain setPassword:@"321321" forService:serviceName account:account]){

    NSLog(@"set success!");

  }

4.删除 

if([SSKeychain deletePasswordForService:serviceName account:account]){

    NSLog(@"delete success!");

  }

说明:删除就是把这一条钥匙删除哦,不是只删除密码!

另外的说明:如果你的password 是NSData

查询: + (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account;

设置or更新:+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account;

下面开始浅浅的理解还有对苹果API进行一点点说明吧

1.Keychain 是什么?

keychain 就是放钥匙柜子!就是苹果提供给我们的一个保险柜。

这篇文章仅针对iOS。

在iOS中每个APP 都有属于自己的Keychain,最常用就是保存用户的账户和密码,就是记住密码,放在这里很安全(苹果负责帮我们加密再存起来,如果出了问题怪他咯!),假如用NSUserDefault 保存这些秘密数据,生成的plist文件(就放在那个Library/Preferences 下)容易被拿到,而且还要自己做加密。

特性:1.当app删除了,又再次重新安装,这个保险柜里的信息还存在哦。 所以当你的某女同学登了APP并保存了密码,你重装了APP,如果不删除记录,你女票还是可以发现的。

   2.安全!作为小白的我并不知道它实际上是存在哪里的。

2.Keychain 组成?

1.组成部分由  {N个标签(属性) + 一个重要数据} 组成!

2.结构可以看成是一个字典的形式大概是这样的: @{@"属性key1":@"属性值1",@"属性keyN":@"属性值N",@"valueData":@数据}

3.内容说明:

一个重要数据:就是密码password!

N个标签:也是属性,都是用来表明这条钥匙的,如我们的serviceName ,account 都是属性,他们对应的键为 kSecAttrAccount 和 kSecAttrAccount,还有系统给我们加的创建时间,修改时间等还有label,type,port,你自己打开文件进去看看吧,这些标签的任务就是来表明这条钥匙是独一无二的。

3.原始API操作

先来看看几个API

添加钥匙:        OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result)

查询密码与查询标签:     OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINEDresult)

更新钥匙信息:             OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)

删除钥匙:        OSStatus SecItemDelete(CFDictionaryRef query)

先说明一下 这些API的关键在于1.是理解和配置好这个操作字典 2.注意返回的OSStatus 状态 3.CF对象与OC 之间的bridge

1.先来一发查找

过程:

1.(关键)先配置一个操作字典内容有:

kSecAttrService(属性),kSecAttrAccount(属性) 这些属性or标签是查找的依据

kSecReturnData(值为@YES 表明返回类型为data),kSecClass(值为kSecClassGenericPassword 表示重要数据为“一般密码”类型) 这些限制条件是返回结果类型的依据

2.然后用查找的API 得到查找状态和返回数据(密码)

3.最后如果状态成功那么将数据(密码)转换成string 返回

//用原生的API 实现查询密码

- (NSString *)passwordForService:(nonnull NSString *)service account:(nonnull NSString *)account{

//生成一个查询用的 可变字典

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:4];

[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; //表明为一般密码可能是证书或者其他东西

[dict setObject:service forKey:(__bridge id)kSecAttrService];    //输入service

[dict setObject:account forKey:(__bridge id)kSecAttrAccount];  //输入account

[dict setObject:@YES forKey:(__bridge id)kSecReturnData];     //返回Data

//查询

OSStatus status = -1;

CFTypeRef result = NULL;

status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);//核心API 查找是否匹配 和返回密码!

if (status != errSecSuccess) { //判断状态

return nil;

}

//返回数据

NSString *password = [[NSString alloc] initWithData:(__bridge_transfer NSData *)result encoding:NSUTF8StringEncoding];//转换成string

return password;

}

说明:其实关键就在于这个操作字典的配置上!

2.添加&更新

说明:当添加的时候我们一般需要判断一下当前钥匙串里面是否已经存在我们要添加的钥匙。如果已经存在我们就更新好了,不存在再添加,所以这两个操作一般写成一个函数搞定吧。

过程关键:1.检查是否已经存在 构建的查询用的操作字典:kSecAttrService,kSecAttrAccount,kSecClass(标明存储的数据是什么类型,值为kSecClassGenericPassword 就代表一般的密码)

   2.添加用的操作字典: kSecAttrService,kSecAttrAccount,kSecClass,kSecValueData

   3.更新用的操作字典1(用于定位需要更改的钥匙):kSecAttrService,kSecAttrAccount,kSecClass

        操作字典2(新信息)kSecAttrService,kSecAttrAccount,kSecClass ,kSecValueData

//用原生的API 添加一条钥匙

-(BOOL)addItemWithService:(NSString *)service account:(NSString *)account password:(NSString *)password{

//先查查是否已经存在

//构造一个操作字典用于查询

NSMutableDictionary *searchDict = [[NSMutableDictionary alloc]initWithCapacity:4];

[searchDict setObject:service forKey:(__bridge id)kSecAttrService];                         //标签service

[searchDict setObject:account forKey:(__bridge id)kSecAttrAccount];                         //标签account

[searchDict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];//表明存储的是一个密码

OSStatus status = -1;

CFTypeRef result =NULL;

status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDict, &result);

if (status == errSecItemNotFound) {                                              //没有找到则添加

NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];    //把password 转换为 NSData

[searchDict setObject:passwordData forKey:(__bridge id)kSecValueData];       //添加密码

status = SecItemAdd((__bridge CFDictionaryRef)searchDict, NULL);             //!!!!!关键的添加API

}else if (status == errSecSuccess){                                              //成功找到,说明钥匙已经存在则进行更新

NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];    //把password 转换为 NSData

NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:searchDict];

[dict setObject:passwordData forKey:(__bridge id)kSecValueData];             //添加密码

status = SecItemUpdate((__bridge CFDictionaryRef)searchDict, (__bridge CFDictionaryRef)dict);//!!!!关键的更新API

}

return (status == errSecSuccess);

}

其他操作的重要都在操作字典上-_-! 有特殊的东东遇到了再写上!

iOS Keychain,SSKeychain,使用 理解 原理的更多相关文章

  1. iOS - keychain 详解及变化

    keychain介绍 iOS keychain 是一个相对独立的空间,保存到keychain钥匙串中的信息不会因为卸载/重装app而丢失, .相对于NSUserDefaults.plist文件保存等一 ...

  2. iOS中的应用启动原理

    iOS中的应用启动原理 来源: http://m.blog.csdn.net/article/details?id=50530090 http://m.warting.com/program/2016 ...

  3. 李洪强iOS开发之RunLoop的原理和核心机制

    李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研 ...

  4. IOS 图片轮播实现原理 (三图)

    IOS 图片轮播实现原理的一种 图片轮播所要实现的是在一个显示区域内通过滑动来展示不同的图片. 当图片较少时我们可以采用在滚动视图上添加很多张图片来实现. 但是如果图片数量较多时,一次性加载过多图片会 ...

  5. [转]iOS hybrid App 的实现原理及性能监测

    转自:http://www.cocoachina.com/ios/20151118/14270.html iOS hybrid App 的实现原理及性能监测 2015-11-18 11:39 编辑:  ...

  6. iOS Category 添加属性实现原理 - 关联对象

    iOS Category 添加属性实现原理 - 关联对象 RunTime为Category动态关联对象 使用RunTime给系统的类添加属性,首先需要了解对象与属性的关系.对象一开始初始化的时候其属性 ...

  7. 《Python爬虫技术:深入理解原理、技术与开发》已经出版,送Python基础视频课程

    好消息,<Python爬虫技术:深入理解原理.技术与开发>已经出版!!!   JetBrains官方推荐图书!JetBrains官大中华区市场部经理赵磊作序!送Python基础视频课程!J ...

  8. [iOS]浅谈NSRunloop工作原理和相关应用

    一. 认识NSRunloop  1.1 NSRunloop与程序运行 那么具体什么是NSRunLoop呢?其实NSRunLoop的本质是一个消息机制的处理模式.让我们首先来看一下程序的入口——main ...

  9. iOS keyChain 的使用

    详细资料,请参看苹果官方文档Keychain Services Reference . ios中的keychain,用于保存用户的机密信息,对keychain的操作有4种,就是 增,删,改,查: Se ...

随机推荐

  1. Mysql --学习:大量数据快速导入导出

    声明:此文供学习使用,原文:https://blog.csdn.net/xiaobaismiley/article/details/41015783 [实验背景] 项目中需要对数据库中一张表进行重新设 ...

  2. UIWebView的高度不对问题

    一般情况,在- (void)webViewDidFinishLoad:(UIWebView *) webView方法里添加如下代码: CGSize actualSize = [webView size ...

  3. Zabbix监控文件是否存在/文件大小

    检查C:\Zabbix\zabbix_agentd.log文件是否存在 zabbix_get -s 10.16.4.1 -k vfs.file.exists[C:\\Zabbix\\zabbix_ag ...

  4. fedora 28/29 配置 C++ 环境

    最近 使用C++ 开发 更换机器的时候,还要重新配置一下 gnu 工具链.于是简单进行了安装了一下: yum install gcc yum install gcc-c++ yum install g ...

  5. [Hive_add_6] Hive 实现 Word Count

    0. 说明 Hive 通过 explode()函数 和 split()函数 实现 WordConut 1. Hive 实现 Word Count 方式一 1.1 思路 将每一行文本变为 Array 数 ...

  6. Python 提案

    学习Java 不可不知JSR,学习Python自然也得知道 PEP了 1- PEP简介 PEP是Python增强提案(Python Enhancement Proposal)的缩写.https://w ...

  7. Python 中的Duck Typing

    在学习Python的时候发现了鸭 子类型这个术语,听起来好像很有意思一样,所以把它记下来. 鸭子类型(Duck Typing)的名字来源于"鸭子测试": "当看到一只鸟走 ...

  8. 【2018.04.19 ROS机器人操作系统】机器人控制:运动规划、路径规划及轨迹规划简介之一

    参考资料及致谢 本文的绝大部分内容转载自以下几篇文章,首先向原作者致谢,希望自己能在这些前辈们的基础上能有所总结提升. 1. 运动规划/路径规划/轨迹规划的联系与区别 https://blog.csd ...

  9. https 建立连接过程

    http://blog.csdn.net/wangjun5159/article/details/51510594 思考问题的顺序 学技术时,总是会问什么?这里也不例外,https为什么会存在,它有什 ...

  10. MySQL大小写敏感的解决方案

    前言:对于MySQL的大小写敏感的影响,笔者在一个小项目中深刻的体会到:当想要查询一条数据时,总是出来两条或多条,后来发现是大小写敏感造成的原因,本文就该问题提出解决方案. 1.MySQL大小写敏感的 ...