標籤:
我們在開放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
:
iOS APP 密碼儲存到鑰匙串