我們在開放APP時,通常要把一些比較重要的用戶信息保留到APP中,我們很多時候的做法是直接裸存到NSUserDefaults。這種做法的很明顯的缺點是不夠安全,以下我們將用代碼封裝一個類,把用戶名賬號密碼等比較重要的信息保存到蘋果自帶的鑰匙串中,這樣除非整個iOS的安全機制被破解,要不然你儲存的東西就會相對的安全,這樣做還有一個好處就是,當用戶刪除該APP,重新下載安裝了,也能讀取到之前保存到鑰匙串里的數據。
直接上代碼:
.h
// // KeychainTool.h // 密碼保存到鑰匙串 // // Created by HO on 16/6/9. // Copyright © 2016年 HO. All rights reserved. // #import <Foundation/Foundation.h> #import <Security/Security.h> @interface YFKeychainTool : NSObject /** * 儲存字符串到🔑鑰匙串 * * @param sValue 對應的Value * @param sKey 對應的Key */ + (void)saveKeychainValue:(NSString *)sValue key:(NSString *)sKey; /** * 從🔑鑰匙串獲取字符串 * * @param sKey 對應的Key * * @return 返回儲存的Value */ + (NSString *)readKeychainValue:(NSString *)sKey; /** * 從🔑鑰匙串刪除字符串 * * @param sKey 對應的Key */ + (void)deleteKeychainValue:(NSString *)sKey; @end
.m
// // KeychainTool.m // 密碼保存到鑰匙串 // // Created by HO on 16/6/9. // Copyright © 2016年 HO. All rights reserved. // #import "YFKeychainTool.h" @implementation YFKeychainTool + (NSMutableDictionary *)getKeychainQuery:(NSString *)service{ return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword, (__bridge_transfer id)kSecClass,service, (__bridge_transfer id)kSecAttrService,service, (__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock, (__bridge_transfer id)kSecAttrAccessible, nil]; } + (void)saveKeychainValue:(NSString *)sValue key:(NSString *)sKey{ NSMutableDictionary * keychainQuery = [self getKeychainQuery:sKey]; SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery); [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:sValue] forKey:(__bridge_transfer id)kSecValueData]; SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL); } + (NSString *)readKeychainValue:(NSString *)sKey { NSString *ret = nil; NSMutableDictionary *keychainQuery = [self getKeychainQuery:sKey]; [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData]; [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit]; CFDataRef keyData = NULL; if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { @try { ret = (NSString *)[NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData]; } @catch (NSException *e) { NSLog(@"Unarchive of %@ failed: %@", sKey, e); } @finally { } } if (keyData) CFRelease(keyData); return ret; } + (void)deleteKeychainValue:(NSString *)sKey { NSMutableDictionary *keychainQuery = [self getKeychainQuery:sKey]; SecItemDelete((__bridge CFDictionaryRef)keychainQuery); } @end
ViewController 調用
// // ViewController.m // 密碼保存到鑰匙串 // // Created by HO on 16/6/9. // Copyright © 2016年 HO. All rights reserved. // #import "ViewController.h" #import "YFKeychainTool.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UITextField *userName; @property (weak, nonatomic) IBOutlet UITextField *password; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)saveBtn:(id)sender { [YFKeychainTool saveKeychainValue:self.userName.text key:@"userName"]; [YFKeychainTool saveKeychainValue:self.password.text key:@"password"]; } - (IBAction)readeBtn:(id)sender { self.userName.text = [NSString stringWithFormat:@"讀取到用戶名:%@",[YFKeychainTool readKeychainValue:@"userName"]]; self.password.text = [NSString stringWithFormat:@"讀取到用戶密碼:%@",[YFKeychainTool readKeychainValue:@"password"]]; } - (IBAction)deleteBtn:(id)sender { [YFKeychainTool deleteKeychainValue:@"userName"]; [YFKeychainTool deleteKeychainValue:@"password"]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end
效果圖: