我的应用程序在登录或登录时存储用户的凭据。当应用程序启动时,如果我们存储了凭据,我会检查didFinishLaunchingWithOptions
。这可以通过点击应用程序图标或从Xcode启动它来启动应用程序。
但是,当应用程序在后台被杀死并由于位置更改更新而被系统重新启动时,defaultCredentialForProtectionSpace
返回的凭据为零。当我再次正常重新启动应用程序时,凭证又会重新开始。
因此当[launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]
为真时,NSURLCredential
返回的NSURLCredentialStorage
为零;如果它是假的,我们会获得预期的凭证。
以下是一些代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Other init things happen here, including setting up the NSURLProtectionSpace
NSURLCredentialStorage *credentialStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSURLCredential *credential = [credentialStorage defaultCredentialForProtectionSpace:self.protectionSpace];
if (credential) {
// do something - XXX this does not happen when app is launched in background
}
}
答案 0 :(得分:3)
事实证明,钥匙串中的NSURLCredentialStorage
集kSecAttrAccessibleWhenUnlocked
用于存储凭据。这意味着当用户设置密码以解锁手机并且手机被锁定时,无法访问凭据。
--- --- EDIT
以上解释了为什么它不起作用,这是我最终实现的解决方案:将钥匙串中的kSecAttrAccessible
更改为kSecAttrAccessibleAfterFirstUnlock
并处理无法访问凭证的问题在极少数情况下,手机重新启动但尚未解锁。
当应用程序位于前台时,钥匙串将以NSURLCredentialStorage
:kSecAttrAccessibleWhenUnlocked
使用的模式解锁。因此,在applicationDidBecomeActive:
中,我们可以从NSURLCredentialStorage
访问Keychain条目并进行更改:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"server.com" accessGroup:nil];
[wrapper setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
// ...
}
上面的代码使用了KeychainItemWrapper的改编版本。原始版本来自Apple,但我的解决方案基于ARCified版本:https://gist.github.com/dhoerl/1170641。您仍然需要更改该版本才能使用kSecClassInternetPassword
代替kSecClassGenericPassword
,这主要意味着您无法使用kSecAttrGeneric
来查询Keychain项目,而是{{1} }。
--- --- EDIT
上述方法适用于iOS 7.x但在iOS 8.x上不再有效。代码运行正常,但Keychain仍使用kSecAttrServer
。
现在唯一的解决方案是只有当你知道你只在前台使用它时才使用kSecAttrAccessibleWhenUnlocked
。否则,您需要使用https://gist.github.com/dhoerl/1170641中的KeychainItemWrapper将凭据自己存储在Keychain中。然后,您可以在存储凭据时自己设置NSURLCredentialStorage
。
示例代码:
kSecAttrAccessibleAfterFirstUnlock