【问题标题】:Problem using KeychainItemWrapper使用 KeychainItemWrapper 的问题
【发布时间】:2010-08-29 16:51:13
【问题描述】:

我使用以下代码从 iPhone 钥匙串中检索登录凭据:

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Test" accessGroup:nil];
NSString *username = [wrapper objectForKey:(id)kSecAttrAccount];
NSString *password = [wrapper objectForKey:(id)kSecValueData];
[wrapper release];

我的印象是用户第一次启动应用程序时,无法从钥匙串中检索用户名和密码,因此usernamepassword 应该等于nil。但是,我无法使用NSLog 打印出任何这些变量。

有什么建议吗?

【问题讨论】:

  • 你能打印什么?为什么不设置断点并在运行时检查对象?
  • 没什么。当我尝试打印对象时没有任何显示。检查它们只会以 0xSOMETHING 的形式显示地址。
  • @Anh 愚蠢的问题,但您是否验证过 wrapper 不为零?另外,我同意 vfn 关于设置断点...
  • 您应该接受 JRG 的回答。这些值最初设置为 @"" 而不是 nil。

标签: iphone keychain


【解决方案1】:
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Test" accessGroup:nil];
NSString *username = [wrapper objectForKey:(id)kSecAttrAccount];
NSString *password = [wrapper objectForKey:(id)kSecValueData];

// initially all these are empty
NSLog(@"username - %@", username); // username - 
NSLog(@"password - %@", password); // password - 

//if empty set your credentials
if ( [username isEqualToString:@""] ) {
    [wrapper setObject:@"your username here" forKey:(id)kSecAttrAccount];
}
if ( [password isEqualToString:@""] ) {
    [wrapper setObject:@"your password here" forKey:(id)kSecValueData];
}

//get the latest credentials - now you have the set values
username = [wrapper objectForKey:(id)kSecAttrAccount];
password = [wrapper objectForKey:(id)kSecValueData];

NSLog(@"username - %@", username); // username - your username here
NSLog(@"password - %@", password); // password - your password here

// reset your keychain items - if  needed
[wrapper resetKeychainItem];
[wrapper release];

【讨论】:

  • 我不确定的部分是“最初所有这些都是空的”。正如我的问题中提到的,我无法让NSLog 打印任何这些值。如果它们为空/nil,我正在尝试调出登录对话框,但它不起作用。
  • 重新启动应用时这些值会保留吗?
【解决方案2】:

您的假设是错误的 - 创建时,“kSecAttrAccount”和“kSecValueData”未设置为零。它们被设置为一个空字符串(即“”)。所以,这段代码将返回 true:

[username isEqualToString:@""]    // returns true on creation

【讨论】:

  • 不是直接比较字符串,而是检查长度。 [username length] > 0
【解决方案3】:

同样的错误,我检查了KeychainItemWrapper.m 文件中writeToKeychain 函数的返回值。返回值等于errSecDuplicateItem。我不知道为什么,但似乎SecItemCopyMatching 功能无法正常工作。 (对于我的其他项目正常工作)。

我现在更改了代码并为我工作: 更新KeychainItemWrapper.m 文件中writeToKeychain 的代码:

- (void)writeToKeychain
{
    NSDictionary *attributes = NULL;
    NSMutableDictionary *updateItem = NULL;
    OSStatus result;



    if (SecItemCopyMatching((CFDictionaryRef)genericPasswordQuery, (CFTypeRef *)&attributes) == noErr)
    {
        // First we need the attributes from the Keychain.
        updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes];
        // Second we need to add the appropriate search key/values.
        [updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];

        // Lastly, we need to set up the updated attribute list being careful to remove the class.
        NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData];
        [tempCheck removeObjectForKey:(id)kSecClass];

#if TARGET_IPHONE_SIMULATOR
        // Remove the access group if running on the iPhone simulator.
        // 
        // Apps that are built for the simulator aren't signed, so there's no keychain access group
        // for the simulator to check. This means that all apps can see all keychain items when run
        // on the simulator.
        //
        // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
        // simulator will return -25243 (errSecNoAccessForItem).
        //
        // The access group attribute will be included in items returned by SecItemCopyMatching,
        // which is why we need to remove it before updating the item.
        [tempCheck removeObjectForKey:(id)kSecAttrAccessGroup];
#endif

        // An implicit assumption is that you can only update a single item at a time.

        result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
        NSAssert( result == noErr, @"Couldn't update the Keychain Item." );
    }
    else
    {
        // No previous item found; add the new one.

        result =  SecItemAdd((CFDictionaryRef)[self dictionaryToSecItemFormat:keychainItemData], NULL);
        NSLog(@"%@",keychainItemData);
        NSLog(@"res : %ld",result);
        if(result == (OSStatus)errSecDuplicateItem)
        {
            NSLog(@"updttttt");
            // First we need the attributes from the Keychain.
            updateItem = [NSMutableDictionary dictionaryWithDictionary:attributes];
            // Second we need to add the appropriate search key/values.
            [updateItem setObject:[genericPasswordQuery objectForKey:(id)kSecClass] forKey:(id)kSecClass];

            // Lastly, we need to set up the updated attribute list being careful to remove the class.
            NSMutableDictionary *tempCheck = [self dictionaryToSecItemFormat:keychainItemData];
            [tempCheck removeObjectForKey:(id)kSecClass];

#if TARGET_IPHONE_SIMULATOR
            // Remove the access group if running on the iPhone simulator.
            // 
            // Apps that are built for the simulator aren't signed, so there's no keychain access group
            // for the simulator to check. This means that all apps can see all keychain items when run
            // on the simulator.
            //
            // If a SecItem contains an access group attribute, SecItemAdd and SecItemUpdate on the
            // simulator will return -25243 (errSecNoAccessForItem).
            //
            // The access group attribute will be included in items returned by SecItemCopyMatching,
            // which is why we need to remove it before updating the item.
            [tempCheck removeObjectForKey:(id)kSecAttrAccessGroup];
#endif

            // An implicit assumption is that you can only update a single item at a time.

            result = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck);
            NSAssert( result == noErr, @"Couldn't update the Keychain Item." );
            return;
        }//if(result == errSecDuplicateItem)*
        NSAssert( result == noErr, @"Couldn't add the Keychain Item." );
    }
}

【讨论】:

    【解决方案4】:

    如果初始值为 nil,则使用

    if ( [username isEqualToString:@""] )
    

    将评估为 FALSE。你可以使用

    if (!username)
    

    改为

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-25
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多