J'ai essayé d'utiliser des références de keychain persistantes dans une application iPhone. J'ai trouvé que si je créais deux éléments de trousseau différents, j'obtiendrais une référence persistante différente à chaque fois (ils ressemblent à 'genp ....... 1', 'genp ....... 2', ...) . Cependant, les tentatives de recherche des éléments par référence persistante ont toujours renvoyé le contenu du premier élément. Pourquoi cela devrait-il être? J'ai confirmé que mon code d'économie de trousseaux créait définitivement de nouveaux éléments dans chaque cas (plutôt que de mettre à jour des éléments existants), et qu'il n'y avait aucune erreur. Et comme je le dis, Keychain Services donne une référence persistante différente pour chaque élément. J'ai réussi à résoudre mon problème immédiat en recherchant des éléments de keychain par attribut plutôt que des références persistantes, mais il serait plus facile d'utiliser des références persistantes, donc j'apprécierais de résoudre ce problème.Pourquoi Keychain Services renvoie-t-il le mauvais contenu de trousseau?
Voici mon code:
- (NSString *)keychainItemWithName: (NSString *)name {
NSString *path = [GLApplicationSupportFolder()
stringByAppendingPathComponent: name];
NSData *persistentRef = [NSData dataWithContentsOfFile: path];
if (!persistentRef) {
NSLog(@"no persistent reference for name: %@", name);
return nil;
}
NSArray *refs = [NSArray arrayWithObject: persistentRef];
//get the data
CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(params, kSecMatchItemList, refs);
CFDictionaryAddValue(params, kSecClass, kSecClassGenericPassword);
CFDictionaryAddValue(params, kSecReturnData, kCFBooleanTrue);
CFDataRef item = NULL;
OSStatus result = SecItemCopyMatching(params, (CFTypeRef *)&item);
CFRelease(params);
if (result != errSecSuccess) {
NSLog(@"error %d retrieving keychain reference for name: %@", result, name);
return nil;
}
NSString *token = [[NSString alloc] initWithData: (NSData *)item
encoding: NSUTF8StringEncoding];
CFRelease(item);
return [token autorelease];
}
- (void)setKeychainItem: (NSString *)newToken forName: (NSString *)name {
NSData *tokenData = [newToken dataUsingEncoding: NSUTF8StringEncoding];
//firstly, find out whether the item already exists
NSDictionary *searchAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
name, kSecAttrAccount,
kCFBooleanTrue, kSecReturnAttributes,
nil];
NSDictionary *foundAttrs = nil;
OSStatus searchResult = SecItemCopyMatching((CFDictionaryRef)searchAttributes,
(CFTypeRef *)&foundAttrs);
if (noErr == searchResult) {
NSMutableDictionary *toStore = [foundAttrs mutableCopy];
[toStore setObject: tokenData forKey: (id)kSecValueData];
OSStatus result = SecItemUpdate((CFDictionaryRef)foundAttrs,
(CFDictionaryRef)toStore);
if (result != errSecSuccess) {
NSLog(@"error %d updating keychain", result);
}
[toStore release];
return;
}
//need to create the item.
CFMutableDictionaryRef params = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(params, kSecClass, kSecClassGenericPassword);
CFDictionaryAddValue(params, kSecAttrAccount, name);
CFDictionaryAddValue(params, kSecReturnPersistentRef, kCFBooleanTrue);
CFDictionaryAddValue(params, kSecValueData, tokenData);
NSData *persistentRef = nil;
OSStatus result = SecItemAdd(params, (CFTypeRef *)&persistentRef);
CFRelease(params);
if (result != errSecSuccess) {
NSLog(@"error %d from keychain services", result);
return;
}
NSString *path = [GLApplicationSupportFolder()
stringByAppendingPathComponent: name];
[persistentRef writeToFile: path atomically: NO];
[persistentRef release];
}