iOS中保存密码,如果要追求安全性,那么使用苹果自带的Keychain Services无疑是最佳选择。如果要在程序中使用Keychain Services,首先要添加Security.framework。
Keychain Services提供了一系列api用以存取和更新keychain item:
SecItemAdd(添加)
SecItemUpdate(更新)
SecItemCopyMatching(查找)
SecItemDelete(删除)
这些方法直接使用有点麻烦,需要进行面向对象的封装。我写了一个简单的例子,只是用来保存用户名和密码,以实现记住密码这项功能。
下面贴一部分代码,完整项目下载:https://github.com/tenric/KeyChainDemo
MyKeyChainHelper.h
#import
@interface MyKeyChainHelper : NSObject
+ (void) saveUserName:(NSString*)userName
userNameService:(NSString*)userNameService
psaaword:(NSString*)pwd
psaawordService:(NSString*)pwdService;
+ (void) deleteWithUserNameService:(NSString*)userNameService
psaawordService:(NSString*)pwdService;
+ (NSString*) getUserNameWithService:(NSString*)userNameService;
+ (NSString*) getPasswordWithService:(NSString*)pwdService;
@end
MyKeyChainHelper.m
#import "MyKeyChainHelper.h"
@implementation MyKeyChainHelper
+ (NSMutableDictionary *)getKeyChainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassGenericPassword,(id)kSecClass,
service, (id)kSecAttrService,
service, (id)kSecAttrAccount,
(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
nil];
}
+ (void) saveUserName:(NSString*)userName
userNameService:(NSString*)userNameService
psaaword:(NSString*)pwd
psaawordService:(NSString*)pwdService
{
NSMutableDictionary *keychainQuery = [self getKeyChainQuery:userNameService];
SecItemDelete((CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:userName] forKey:(id)kSecValueData];
SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
keychainQuery = [self getKeyChainQuery:pwdService];
SecItemDelete((CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:pwd] forKey:(id)kSecValueData];
SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}
+ (void) deleteWithUserNameService:(NSString*)userNameService
psaawordService:(NSString*)pwdService
{
NSMutableDictionary *keychainQuery = [self getKeyChainQuery:userNameService];
SecItemDelete((CFDictionaryRef)keychainQuery);
keychainQuery = [self getKeyChainQuery:pwdService];
SecItemDelete((CFDictionaryRef)keychainQuery);
}
+ (NSString*) getUserNameWithService:(NSString*)userNameService
{
NSString* ret = nil;
NSMutableDictionary *keychainQuery = [self getKeyChainQuery:userNameService];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr)
{
@try
{
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData];
}
@catch (NSException *e)
{
NSLog(@"Unarchive of %@ failed: %@", userNameService, e);
}
@finally
{
}
}
if (keyData)
CFRelease(keyData);
return ret;
}
+ (NSString*) getPasswordWithService:(NSString*)pwdService
{
NSString* ret = nil;
NSMutableDictionary *keychainQuery = [self getKeyChainQuery:pwdService];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr)
{
@try
{
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData];
}
@catch (NSException *e)
{
NSLog(@"Unarchive of %@ failed: %@", pwdService, e);
}
@finally
{
}
}
if (keyData)
CFRelease(keyData);
return ret;
}
@end