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 と google を検索しましたが、 で値を取得できませんNSLog

その理由は何ですか?

編集 :

キーチェーンを操作するために、誰かが持っている場合は、他の情報を提供することもできますか?

4

3 に答える 3

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
于 2013-11-19T16:16:00.987 に答える
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 クラスも必要です。ARC 化され、わずかに変更された (辞書を処理するための) KeyChainItemWrapper バージョンを取得できます。必要な 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

ご覧のとおり、必要に応じてコメントを解除して動作を確認できるログ メッセージが多数あります。

このコードは、配送アプリで使用されました。

于 2013-11-19T17:18:06.930 に答える