前言 :
項目中有時會須要存儲敏感信息(如密碼、密鑰等),蘋果官方提供了一種存儲機制--鑰匙串(keychain)
。
keychain是一種存儲在硬盤
上的加密的數據庫
。這個多是卸載App後,keychain信息還在的緣由。
keychain適合存儲較小的數據量
(不超過上千字節或上兆字節
)的內容。
筆者作了一個關於keychain的增、刪、改、查
的Demo(QiKeychain),給你們介紹下keychain的基本使用。ios
下圖(確保keychain中用戶的信息安全)有利於咱們直觀瞭解keychain。 git
![]()
筆者用Demo(QiKeychain)作了4件事。github
- 增長:存儲用戶名、密碼到keychain;
- 查詢:根據用戶名從keychain中查詢密碼;
- 刪除:從keychain中刪除用戶名、密碼等相應信息;
- 修改:修改keychain中的用戶名對應的密碼;
Demo(QiKeychain)對keychain的操做效果以下:數據庫
- 存儲用戶名 「QiShare」,密碼:1234;
- 查詢用戶名爲「QiShare」的密碼,顯示密碼爲:1234;
- 修改用戶名「QiShare」的密碼爲「123456」;
- 查詢「QiShare」的密碼,顯示爲「123456」;
- 把「QiShare」從keychain中刪除。
keychain有四個經常使用的API,用於增、刪、改、查keychain中的數據。
keychain中的數據子項是以item的形式存在的。
舉個例子:就存儲用戶名、密碼的情景來講,每一個item包含存儲的用戶名和密碼及其餘屬性信息,keychain中包含多個用戶名和密碼的item。macos
下圖(把數據和屬性存儲到keychain中)利於咱們理解存儲過程 安全
![]()
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result)
API_AVAILABLE(macos(10.6), ios(2.0));
複製代碼
存儲關鍵代碼:bash
NSDictionary *saveSecItems = @{(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: service,
(id)kSecAttrAccount: account,
(id)kSecValueData: passwordData
};
OSStatus saveStatus = SecItemAdd((CFDictionaryRef)saveSecItems, NULL);
複製代碼
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINED result)
API_AVAILABLE(macos(10.6), ios(2.0));
複製代碼
查詢關鍵代碼:微信
NSDictionary *matchSecItems = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: service,
(id)kSecAttrAccount: account,
(id)kSecMatchLimit: (id)kSecMatchLimitOne,
(id)kSecReturnData: @(YES)
};
CFTypeRef dataRef = nil;
OSStatus errorCode = SecItemCopyMatching((CFDictionaryRef)matchSecItems, (CFTypeRef *)&dataRef);
複製代碼
OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)
API_AVAILABLE(macos(10.6), ios(2.0));
複製代碼
注意:更新代碼這部分,筆者開始的時候遇到一些問題,還要多謝組內成員,尤爲是昆哥的指教。
SecItemUpdate接收了2個參數,query和attributesToUpdate。
第一個參數query用於查詢到相應的item, 第二個參數attributesToUpdate用於傳入要更新的信息。
筆者曾錯誤地給第二個參數attributesToUpdate傳入過(id)kSecClass: (id)kSecClassGenericPassword要更改的內容。
結果報錯爲:
errSecNoSuchAttr = -25303, /* The specified attribute does not exist. */
網絡
更新關鍵代碼:
NSDictionary *queryItems = @{(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: service,
(id)kSecAttrAccount: account
};
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *updatedItems = @{
(id)kSecValueData: passwordData,
};
OSStatus updateStatus = SecItemUpdate((CFDictionaryRef)queryItems, (CFDictionaryRef)updatedItems);
複製代碼
OSStatus SecItemDelete(CFDictionaryRef query)
API_AVAILABLE(macos(10.6), ios(2.0));
複製代碼
刪除關鍵代碼:
NSDictionary *deleteSecItems = @{
(id)kSecClass: (id)kSecClassGenericPassword,
(id)kSecAttrService: service,
(id)kSecAttrAccount: account
};
OSStatus errorCode = SecItemDelete((CFDictionaryRef)deleteSecItems);
複製代碼
增刪改查
相關的API都須要設置相應的屬性字典
(分別代指上述的saveSecItems 、matchSecItems 、queryItems 、updatedItems 、deleteSecItems)
- (id)kSecClass: (id)kSecClassGenericPassword kSecClass表示item的class (id)kSecClass的值代表一個通用的密碼item筆者通常都傳入kSecClassGenericPassword
- (id)kSecAttrService: service kSecAttrService的value用於代表item的service
- (id)kSecAttrAccount: account (id)kSecAttrAccoun的值代表item的賬戶名
- (id)kSecValueData: passwordData (id)kSecValueData表示item的數據
- (id)kSecMatchLimit: (id)kSecMatchLimitOne, (id)kSecMatchLimit 有2個值(id)kSecMatchLimitOne、和(id)kSecMatchLimitAll kSecMatchLimitOne:表示只匹配第一個符合條件的item kSecMatchLimitAll:表示匹配不限數量的items
- (id)kSecReturnData: @(YES) (id)kSecReturnData的值是一個Boolean類型的值用於肯定是否返回item data
- kSecClass的值表示item的class kSecClass的值代表一個通用的密碼item筆者通常都傳入的kSecClassGenericPassword
- kSecClass的值表示item的class kSecClass的值代表一個通用的密碼item筆者通常都傳入的kSecClassGenericPassword
在Demo(QiKeychain)中,筆者對keychain相關使用的API進行了封裝。獲取Demo(QiKeychain)GitHub地址:QiKeychain。
注意:
筆者後來封裝的代碼,修改了保存操做的邏輯。
修改內容爲:在保存用戶名密碼的時候
-> 先在keychain中查詢
用戶名是否存在
-> 若存在,就進行更新
操做;
-> 若不存在就進行保存
操做。
相應示意圖(使用鑰匙串存儲網絡密碼)以下:
![]()
小編微信:可加並拉入《QiShare技術交流羣》。
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)
推薦文章:
iOS 自定義拖拽式控件:QiDragView
iOS 自定義卡片式控件:QiCardView
iOS Wireshark抓包
iOS Charles抓包
初探TCP
IP、UDP初探
奇舞週刊