不从后台检索值

我目前存储的用户名(电子邮件)和电子邮件和密码在 iOS 钥匙链盐散列。我正在使用发现的 给你的 ARC 化版本。

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
[wrapper setObject:APP_NAME forKey:(__bridge id)kSecAttrService];
[wrapper setObject:email forKey:(__bridge id)kSecAttrAccount];
[wrapper setObject:token forKey:(__bridge id)kSecValueData];

当我需要在应用程序处于活动状态时为我的网络调用取出令牌时,这一切都工作得很好。它适用于从一个干净的启动登录,以及整个网络调用。当应用程序在后台时,麻烦就开始了。

请记住,这种情况只是偶尔发生,我还没有把它确定为特定的 iOS 版本或设备。

用户跳过一个位置(区域监视) ,我想更新他们的状态服务器。我尝试从密钥链中取出令牌,就像我对其他网络调用所做的那样,并更新状态。但对于一些用户来说,它的价值为零。没有它,我没法更新网络。为什么这对大多数人有效,但对一小部分人不行呢?

KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
NSString *token = [wrapper objectForKey:(__bridge id)kSecValueData];

我回到了 keychainwrapper 的非 ARC 版本,但仍然得到相同的结果。如果有任何反馈,我将不胜感激。这只是我的用户的一小部分,但这是一个问题,我想修复,而不是担心。先谢谢你。

另外,我所有的后台工作都设置在 backoundTask 中,以防止超时。我对钥匙链的工作没有任何问题,但是在我的令牌被填满之前,我不会让事情向前发展。

剪辑 我已经解决了我的问题,他们的钥匙链不检索值从背景。我将在下面发布答案,并接受它,因为我觉得这个问题可能会变得对其他人有价值。

27614 次浏览

My question was close to the mark for the reason why, but not quite. After reading through blog after blog, tutorial after tutorial, I finally found one that gave off a hint of what might be happening.

Locked home screens. The keychain tutorials always left the accessibility settings for the keychain blank, so it would default to Apple's lowest/safest access level. This level however doesn't allow keychain access if the user has a passcode on the lock screen. Bingo! This explains the sporadic behavior and why this only happens to a small percentage of users.

One line of code, solves the entire mess.

[wrapper setObject:(__bridge id)kSecAttrAccessibleAlways forKey:(__bridge id)kSecAttrAccessible];

Add this line where I'm setting the username and password values. Works like a charm. Hope this will help someone out there. It confounded me for quite a while until I was able to put the pieces together.

Use kSecAttrAccessibleAfterFirstUnlock instead of kSecAttrAccessibleAlways.


From Apple's documentation:

kSecAttrAccessibleAfterFirstUnlock
The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user.

After the first unlock, the data remains accessible until the next restart. This is recommended for items that need to be accessed by background applications. Items with this attribute migrate to a new device when using encrypted backups.

In my case, watchOS2 accesses keychain data on the iOS side.

At the beginning, kSecAttrAccessibleWhenUnlockedThisDeviceOnly is used. I can read the data no matter iPhone is locked or not. It is very confusing to me that I will receive Error when watch is trying to access the keychain: : SecTrustEvaluate [leaf IssuerCommonName SubjectCommonName]

And some case it will become: : SecOSStatusWith error:[-25308] Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'oe' item (class 6, bag: 0) Access to item attempted while keychain is locked." UserInfo={NSDescription=ks_crypt: e00002e2 failed to 'oe' item (class 6, bag: 0) Access to item attempted while keychain is locked.}

I will update my answer if I get more infos.

This might happen due to Apples data protection policy which is at some level obscure from developers perspective. Workaround is when app's launched check if keychain is accessible or not, if not accessible you might kill your app (with proper popup) depending your app types.

+(BOOL) isKeychainAccessible
{
NSString *keychainTestKey = @"keychainTestKey";
NSString *keychainTestValue = @"keychainTestValue";
[self createKeychainValue:keychainTestValue forIdentifier:keychainTestKey];
NSString *loadedValue = [self keychainStringFromMatchingIdentifier:keychainTestKey];
[self deleteItemFromKeychainWithIdentifier:keychainTestKey];
return ([keychainTestValue isEqualToString: loadedValue]);
}