我使用以下内容在钥匙串中存储值:
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"suggest" accessGroup:nil];
[keychain setObject:[object valueForKey:@"token"] forKey:(__bridge id)(kSecValueData)];
[keychain setObject:[object valueForKey:@"usr_id"] forKey:(__bridge id)(kSecAttrAccount)];
以下是我检索值的代码:
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"suggest" accessGroup:nil];
NSLog(@"TOKEN:%@",[keychain objectForKey:(__bridge id)(kSecValueData)]);
NSLog(@"USER NAME:%@",[keychain objectForKey:(__bridge id)(kSecAttrAccount)]);
我还包括了安全框架。
我搜索了stackoverflow和google,但无法在NSLog
中获取值。
可能是什么原因?
编辑:
如果有人有,为了使用钥匙串,还可以提供其他信息吗?
答案 0 :(得分:3)
我使用答案因为评论有限...... 我尝试了一个新项目的以下代码,下载KeychainItemWrapper并链接Security.framework
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
{
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"suggest" accessGroup:nil];
[keychain setObject:@"aaaa" forKey:(__bridge id)(kSecValueData)];
[keychain setObject:@"bbbb" forKey:(__bridge id)(kSecAttrAccount)];
NSLog(@"TOKEN:%@",[keychain objectForKey:(__bridge id)(kSecValueData)]);
NSLog(@"USER NAME:%@",[keychain objectForKey:(__bridge id)(kSecAttrAccount)]);
}
{
KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"suggest" accessGroup:nil];
NSLog(@"TOKEN:%@",[keychain objectForKey:(__bridge id)(kSecValueData)]);
NSLog(@"USER NAME:%@",[keychain objectForKey:(__bridge id)(kSecAttrAccount)]);
}
// Override point for customization after application launch.
return YES;
}
一切都很完美。我想你需要提供更多的代码才能找到答案。这是我的日志:
2013-11-19 17:11:08.378 test[3430:a0b] TOKEN:aaaa
2013-11-19 17:11:08.379 test[3430:a0b] USER NAME:bbbb
2013-11-19 17:11:08.380 test[3430:a0b] TOKEN:aaaa
2013-11-19 17:11:08.381 test[3430:a0b] USER NAME:bbbb
答案 1 :(得分:1)
以下是工作代码,它允许您维护与主键相关的数据字典" (此处的电子邮件地址可能是您应用中的任何主要标识符。)
其他键存储在任意大小的字典中,并放入"密码" keyChain对象。
首先,我将它放在AppDelegate.h文件的底部:
#define kEmail @"email"
#define kPassword @"pass"
#define kSomeOtherItemA @"a_item"
#define kSomeOtherItemB @"b_item"
@interface AppDelegate (Keychain)
- (NSDictionary *)keychainDictionary; // current keyChain dictionary
- (void)eraseKeychain; // total wipe it
- (void)erasePassword; // wipe the password
@end
您可以根据需要在此处添加特殊方法。通过放置这是AppDelegate.h文件,导入该文件的任何其他类都可以使用这些方法。如果你想将它私有移动到你的AppDelegate.m文件
这在你的AppDelegate.m文件中,在顶部:
@interface AppDelegate (KeychainPrivate)
- (void)updateKeychainItem:(NSString *)item forKey:(NSString *)key; //the password, or itemA, or itemB
- (id)keychainItemForKey:(NSString *)key; // the password, itemA, itemB, ...
@end
这可以放在AppDelegate.m的底部或单独的文件中:
static char *kcIdentifier = "foo"; // use any string you want instead of "foo"
@implementation AppDelegate (Keychain)
- (KeychainItemWrapper *)keyChainItemWrapper
{
static dispatch_once_t pred;
static KeychainItemWrapper *kciw;
dispatch_once(&pred, ^
{
kciw = [[KeychainItemWrapper alloc] initWithIdentifier:kcIdentifier accessGroup:nil];
} );
return kciw;
}
- (NSDictionary *)keychainDictionary
{
NSMutableDictionary *mDict = [NSMutableDictionary dictionaryWithCapacity:3];
KeychainItemWrapper *kcItem = [self keyChainItemWrapper];
NSString *emailAddr = [kcItem objectForKey:(__bridge id)kSecAttrAccount];
if([emailAddr length]) {
NSData *data = [kcItem objectForKey:(__bridge id)kSecValueData];
if([data length]) {
NSKeyedUnarchiver *kua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
NSDictionary *dict = [kua decodeObject];
[kua finishDecoding];
[mDict addEntriesFromDictionary:dict];
}
mDict[kEmail] = emailAddr; // last in case it got in the dictionary somehow
}
return mDict;
}
- (void)eraseKeychain
{
KeychainItemWrapper *kcItem = [self keyChainItemWrapper];
[kcItem resetKeychainItem];
}
- (void)erasePassword
{
[self updateKeychainItem:@"" forKey:kPassword];
}
@end
@implementation AppDelegate (KeychainPrivate)
- (void)updateKeychainItem:(NSString *)item forKey:(NSString *)key
{
KeychainItemWrapper *kcItem = [self keyChainItemWrapper];
// NSLog(@"SET KC key=%@ ITEM %@", key, item);
// NSLog(@"CURRENT KEYCHAIN: %@", [self keychainDictionary]);
if([key isEqualToString:kEmail]) {
NSString *emailAddr = [kcItem objectForKey:(__bridge id)kSecAttrAccount];
if(![emailAddr isEqualToString:item]) {
[kcItem setObject:item forKey:(__bridge id)kSecAttrAccount];
// NSLog(@"SET KC Account ITEM %@", item);
}
// NSLog(@"KC Account ITEM %@ ALREADY SET", item);
} else {
NSData *data = [kcItem objectForKey:(__bridge id)kSecValueData];
//NSLog(@"KC get DATA len=%d", [data length]);
NSDictionary *dict;
if([data length]) {
NSKeyedUnarchiver *kua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
dict = [kua decodeObject];
[kua finishDecoding];
} else {
dict = [NSDictionary dictionary];
}
//NSLog(@"KC OLD DICT %@", dict);
if(![item isEqualToString:dict[key]]) {
//NSLog(@"KC DATA NOT EQUAL");
NSMutableDictionary *mDict = [NSMutableDictionary dictionaryWithDictionary:dict];
mDict[key] = item;
NSMutableData *tmpData = [NSMutableData dataWithCapacity:256];
NSKeyedArchiver *ka = [[NSKeyedArchiver alloc] initForWritingWithMutableData:tmpData];
[ka encodeObject:mDict];
[ka finishEncoding];
//NSLog(@"KC ENCODE MDICT %@", mDict);
[kcItem setObject:tmpData forKey:(__bridge id)kSecValueData];
//NSLog(@"SET KC DATA LEN=%d", [tmpData length]);
}
}
//NSLog(@"JUST UPDATED KEYCHAIN KEY=%@ val=%@ read dict back=%@", key, item, [self keychainDictionary]);
}
- (id)keychainItemForKey:(NSString *)key
{
NSDictionary *dict = [self keychainDictionary];
return dict[key];
}
@end
您还需要KeyChainItemWrapper类。您可以获得ARCified并稍加修改(以便处理字典)KeyChainItemWrapper version。你可以真正使用你想要的任何KeyChainWrapper文件,但是需要进行这种更改(除了ARC化之外,这是对Apple代码的唯一更改):
// Default data for keychain item.
#ifndef PASSWORD_USES_DATA
[keychainItemData setObject:@"" forKey:(__bridge id)kSecValueData];
#else
[keychainItemData setObject:[NSData data] forKey:(__bridge id)kSecValueData];
#endif
正如您所看到的,如果您愿意,可以取消注释许多日志消息,以便查看它。
此代码用于运送应用程序。
答案 2 :(得分:0)