2013-11-14 62 views
2

我使用在鑰匙串下面來存儲值:無法存儲在鑰匙串中值正確

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和谷歌,但我無法獲得值在NSLog

可能是什麼原因?

編輯:

你也可以給我提供其他信息,如果任何人有,爲了與鑰匙串工作?

+0

你的代碼應工作 - 你確定你的字典裏'object'真正保存的數據在你寫信給鑰匙鏈的那一刻。 –

+0

是的,我在應用程序級別使用相同的變量,但我需要移動鑰匙串。它真的持有價值。這應該是其他問題。 – astuter

+0

您是否在設置它們之後嘗試使用您的代碼來檢索值? – AncAinu

回答

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 
+0

你是什麼意思「下載...並鏈接Security.framework」?我也從項目設置中將它鏈接起來。還有什麼要做? – astuter

+0

哦,對不起,它是「下載KeychainItemWrapper並鏈接Security.framework」。這裏是我的DL鏈接:https://www.dropbox.com/s/mjkm8u0z2ybhcvf/KeyChainWrapper_ARCSupported.zip – AncAinu

+0

我編輯,我的道歉,只是寫了,並沒有檢查回 – AncAinu

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文件,但需要做出這種改變(這是蘋果的代碼,唯一的變化比ARCifying它其他):

// 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 

正如你所看到的,有很多日誌消息,你的如果你願意,可以取消註釋以看到它在行動中。

此代碼被用於航運應用程序。

0

如果您正在使用xCode 8.0請做如下:

Project Navigator -> Select Target -> Capabilities 

啓用KeyChain SharingON

enter image description here

相關問題