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. c/c++线性队列

    线性队列 队列是先进先出,和栈相反. 不循环的队列就是浪费空间,如果tail到了最大值后,即使前面出队了,有空的位置,也不能再入队. seqqueue.h #ifndef __SEQQUEUE__ # ...

  2. 编写脚本实现DHCP服务与DHCP中继自动化执行

    编写脚本实现DHCP服务与DHCP中继自动化执行 本脚本是在liunx搭建DHCP服务器以及DHCP中继服务器实验环境下实现的https://www.cnblogs.com/yuzly/p/10539 ...

  3. ubuntu 打开eclipse出现A Java Runtime Environment (JRE) or Java Development Kit (JDK) must be ... 解决方法(转载)

    原创作者:http://www.cnblogs.com/jerome-rong/archive/2013/02/19/2916608.html Java RunTime Environment (JR ...

  4. 简述openstack

    大家好,我顾某人又回来了,开学第一更.... 以下内容均为个人理解和整理,有不对的地方还望dalao指正..... 本文所用图片均已标明来源. openstack是什么? OpenStack是一个开源 ...

  5. February 17th, 2018 Week 7th Saturday

    The happiest part of a man's life is what he passes lying awake in bed in the morning. 人生一大乐事莫过去早上醒来 ...

  6. 《Java大学教程》—第14章 抽象、继承和接口

    自测题:1.    解释抽象和抽象数据类型的概念.P333抽象的概念是仅仅关注对象可以完成什么工作,而不必担心如何完成工作的细节.类模板通常被称为抽象数据类型.因为这类数据暴露给用户的所有信息仅仅是方 ...

  7. Nginx使用教程(二):Nginx配置性能优化之worker配置

    配置Nginx workers <br\>NGINX根据指定的配置运行固定数量的工作进程. 这些工作进程负责处理所有处理. 在下面的章节中,我们将调整NGINX worker参数. 这些参 ...

  8. [CQOI2017]老C的键盘

    [CQOI2017]老C的键盘 题目描述 额,网上题解好像都是用的一大堆组合数,然而我懒得推公式. 设\(f[i][j]\)表示以\(i\)为根,且\(i\)的权值为\(j\)的方案数. 转移: \[ ...

  9. xpath 解析 及案例

    xpath解析 编码流程: 1.实例化一个etree对象,且将页面源码加载到该对象中 2.使用xpath函数,且在函数中必须作用一个xpath表达式进行标签的定位 3.使用xpath进行属性和文本的提 ...

  10. P1705 爱与愁过火(背包)

    本来是个搜索题,但是自觉的成了背包! 多重用正序,01用逆序. 抽象出来一下,一个物体的体积为ai, 每次装入背包需要bi(在题目中为菜数量)分钟(这个题目只是bi为 1 而已)问在r分钟内,装比n大 ...