82-Swift之密码管理(Keychain)的介绍和使用

引言

App的开发中,用户登录的模块是必不可少的。用户登录一次之后,就可以使用自动登录功能。自动登录需要知道用户的账号和密码。那么用户的账户和密码是保密性的,为实现App的自动登录功能,我们要稳妥的管理好用户的账号和密码的安全。所以 Keychain 就被使用的上了。下面将给你介绍 Keychain 是什么、如何使用等。友情链接:Object-C 版的密码管理 Keychain 的连接地址 iOS的密码管理系统 Keychain的介绍和使用

Keychain 是什么?

Keychain 是苹果公司 Mac OS(也包含 Mac OSX) 中的密码管理系统。

Keychain 的作用是什么?

Keychain 可以包含许多种类型的数据:密码(包括网站、FTP服务器、SSH账户、网络共享、无线网络、群组软件、加密磁盘镜像),私钥,电子证书、加密笔记等。

Keychain 的四个方法的介绍

1、数据的存储方法

@available(iOS 2.0, *)
public func SecItemAdd(_ attributes: CFDictionary, _ result: UnsafeMutablePointer<CoreFoundation.CFTypeRef?>?) -> OSStatus

@ attributes  : 要存储的数据。
@ result : 存储数据后,返回的指向该数据的引用。

2、根据查询条件获取数据

@available(iOS 2.0, *)
public func SecItemCopyMatching(_ query: CFDictionary, _ result: UnsafeMutablePointer<CoreFoundation.CFTypeRef?>?) -> OSStatus

@ query  :  获取数据的查询条件。
@ result  :  查询后获取到数据的引用。

3、更新数据

@available(iOS 2.0, *)
public func SecItemUpdate(_ query: CFDictionary, _ attributesToUpdate: CFDictionary) -> OSStatus

@ query : 要更新数据的查询条件。
@ attributesToUpdate : 要更新的数据内容。

4、删除数据

@available(iOS 2.0, *)
public func SecItemDelete(_ query: CFDictionary) -> OSStatus

@ query : 删除数据的查询条件。

总结,以上四个方法,就是 Keychain 的增、删、改、查的四个基本方法。这四个方法基本满足大部分App的使用需求。

Keychain 的整理和封装为一个类: KeychainManager.swift

KeychainManager.swift 的完整代码展示:

//
//  KeychainManager.swift
//  KeyChain
//
//  Created by MAC on 2017/11/20.
//  Copyright © 2017年 NetworkCode小贱. All rights reserved.
//

import UIKit

class KeychainManager: NSObject {
    // TODO: 创建查询条件
    class func createQuaryMutableDictionary(identifier:String)->NSMutableDictionary{
        // 创建一个条件字典
        let keychainQuaryMutableDictionary = NSMutableDictionary.init(capacity: 0)
        // 设置条件存储的类型
        keychainQuaryMutableDictionary.setValue(kSecClassGenericPassword, forKey: kSecClass as String)
        // 设置存储数据的标记
        keychainQuaryMutableDictionary.setValue(identifier, forKey: kSecAttrService as String)
        keychainQuaryMutableDictionary.setValue(identifier, forKey: kSecAttrAccount as String)
        // 设置数据访问属性
        keychainQuaryMutableDictionary.setValue(kSecAttrAccessibleAfterFirstUnlock, forKey: kSecAttrAccessible as String)
        // 返回创建条件字典
        return keychainQuaryMutableDictionary
    }
    
    // TODO: 存储数据
    class func keyChainSaveData(data:Any ,withIdentifier identifier:String)->Bool {
        // 获取存储数据的条件
        let keyChainSaveMutableDictionary = self.createQuaryMutableDictionary(identifier: identifier)
        // 删除旧的存储数据
        SecItemDelete(keyChainSaveMutableDictionary)
        // 设置数据
        keyChainSaveMutableDictionary.setValue(NSKeyedArchiver.archivedData(withRootObject: data), forKey: kSecValueData as String)
        // 进行存储数据
        let saveState = SecItemAdd(keyChainSaveMutableDictionary, nil)
        if saveState == noErr  {
            return true
        }
        return false
    }

    // TODO: 更新数据
    class func keyChainUpdata(data:Any ,withIdentifier identifier:String)->Bool {
        // 获取更新的条件
        let keyChainUpdataMutableDictionary = self.createQuaryMutableDictionary(identifier: identifier)
        // 创建数据存储字典
        let updataMutableDictionary = NSMutableDictionary.init(capacity: 0)
        // 设置数据
        updataMutableDictionary.setValue(NSKeyedArchiver.archivedData(withRootObject: data), forKey: kSecValueData as String)
        // 更新数据
        let updataStatus = SecItemUpdate(keyChainUpdataMutableDictionary, updataMutableDictionary)
        if updataStatus == noErr {
            return true
        }
        return false
    }
    
    
    // TODO: 获取数据
    class func keyChainReadData(identifier:String)-> Any {
        var idObject:Any?
        // 获取查询条件
        let keyChainReadmutableDictionary = self.createQuaryMutableDictionary(identifier: identifier)
        // 提供查询数据的两个必要参数
        keyChainReadmutableDictionary.setValue(kCFBooleanTrue, forKey: kSecReturnData as String)
        keyChainReadmutableDictionary.setValue(kSecMatchLimitOne, forKey: kSecMatchLimit as String)
        // 创建获取数据的引用
        var queryResult: AnyObject?
        // 通过查询是否存储在数据
        let readStatus = withUnsafeMutablePointer(to: &queryResult) { SecItemCopyMatching(keyChainReadmutableDictionary, UnsafeMutablePointer($0))}
        if readStatus == errSecSuccess {
            if let data = queryResult as! NSData? {
                idObject = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as Any
            }
        }
        return idObject as Any
    }
    
    
    
    // TODO: 删除数据
    class func keyChianDelete(identifier:String)->Void{
        // 获取删除的条件
        let keyChainDeleteMutableDictionary = self.createQuaryMutableDictionary(identifier: identifier)
        // 删除数据
        SecItemDelete(keyChainDeleteMutableDictionary)
    }
}

上面展示的代码已经注释非常详细了,就不在多介绍了。如果还有不了解的地方可以查看iOS版本的Keychain,连接如下:iOS的密码管理系统 Keychain的介绍和使用

KeychainManager.swift 类的测试和使用

1、测试代码

// 存储数据
let saveBool = KeychainManager.keyChainSaveData(data: "我期待的女孩" as Any, withIdentifier: KeyChain)
if saveBool {
    print("存储成功")
}else{
    print("存储失败")
}
// 获取数据
let getString = KeychainManager.keyChainReadData(identifier: KeyChain) as! String
print(getString)


// 更新数据
let updataBool = KeychainManager.keyChainUpdata(data: "眼睛像云朵", withIdentifier: KeyChain)
if updataBool {
    print("更新成功")
}else{
    print("更新失败")
}
// 获取更新后的数据
let getUpdataString = KeychainManager.keyChainReadData(identifier: KeyChain) as! String
print(getUpdataString)


// 删除数据
KeychainManager.keyChianDelete(identifier: KeyChain)
// 获取删除后的数据
let getDeleteString = KeychainManager.keyChainReadData(identifier: KeyChain)
print(getDeleteString)

2、测试结果的展示

DAB86C95-248D-45B7-B9B6-D748DB7F9BE1.png

下载Demo 的方法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • CGI是web服务器调用外部服务器时所使用的一种服务端应用的规范。一般的web通信中,只是按照客户端请求保存在we...
    followyounger1阅读 195评论 0 0
  • 人生最痛苦的事,莫过于不断努力,但梦想永远无法实现。 希望我成功的速度比父母老去的速度快。 我之所以努力,是为了能...
    克合尕尔阅读 248评论 0 0
  • 远处的山呐 有没有去你那的近路 你看那太阳就要下山了 远处的山呐 请告诉我一条坦途 我的脚都被荆棘划烂了 远处的山...
    6986288f0d8f阅读 221评论 0 2
  • (一) 曾无数次动过回老家生活的...
    周世恩阅读 967评论 0 0