无法使用不同的NSURLCredential进行身份验证(使用旧的已删除的)

时间:2011-09-19 12:45:24

标签: objective-c cocoa nsurlconnection nsurlcredential

我一直在搜索stackoverflow,谷歌,苹果和其他地方。提供的提示看起来很有前途,我实现了它们但总的来说似乎没有工作或得到强制执行。

问题:我有NSURLConnection具有特定凭据。然后我退出登录,清除凭据,保护空间,我删除所有缓存的响应并删除sharedHTTPCookieStorage中的所有cookie但几秒钟后再次调用我的身份验证请求,即使使用了错误的凭据我还在使用旧(已删除)凭据

以下是一些代码摘录,其中删除了凭据

        NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];

    if ([credentialsDict count] > 0) {
        // the credentialsDict has NSURLProtectionSpace objs as keys and dicts of userName => NSURLCredential
        NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
        id urlProtectionSpace;

        // iterate over all NSURLProtectionSpaces
        while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
            NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator];
            id userName;

            // iterate over all usernames for this protectionspace, which are the keys for the actual NSURLCredentials
            while (userName = [userNameEnumerator nextObject]) {
                NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userName];
                WriteLog(@"Method: switchView removing credential %@",[cred user]);
                [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
            }
        }
    }

然后删除所有缓存的响应

    NSURLCache *sharedCache = [NSURLCache sharedURLCache];
    [sharedCache removeAllCachedResponses];

然后删除所有Cookie

    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *cookies = [cookieStorage cookies];
    for (NSHTTPCookie *cookie in cookies) {
        [cookieStorage deleteCookie:cookie];
        NSLog(@"deleted cookie");
    }

我也尝试过不使用cookie和其他政策

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
[request setHTTPShouldHandleCookies:NO];
if(self.currentCookies != nil){
    [request setAllHTTPHeaderFields:
     [NSHTTPCookie requestHeaderFieldsWithCookies:nil]];
}

theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

我也尝试过这个提示,专门存储cookie并再次传递它们。 http://www.hanspinckaers.com/multiple-nsurlrequests-with-different-cookies。网上有另一个博客建议为每个URL添加一个“#”以强制执行重新认证,这可以解决问题,因为我需要依靠会话的凭据和使用完全不同的凭据的能力。

这是一个错误或已知问题,我该如何解决这个问题...... 直言不讳:我在这里做错了什么?

这真让我烦恼,不让我继续工作。

我非常感谢任何输入!

非常感谢!

6 个答案:

答案 0 :(得分:7)

不幸的是,似乎没有解决这个问题的方法。

您可以使用NSURLCredentialPersistenceNone或#技巧,也可以定义'connectionShouldUseCredentialStorage'委托方法以返回NO。如果您每次都这样做并且您的应用程序永远不会保留会话的凭据,那么将强制在每个请求上发生挑战。

对于仅执行最少请求或最终使用会话cookie进行身份验证的应用,这可能正常。

对于发送大量请求的应用,这些解决方案都会针对每个请求产生401响应,并且额外的质询响应可以在数据和性能方面加起来。

如果您可以保留会话的凭据存储,直到您需要注销然后切换到其中一种解决方案,那将是很好的,但这是不可能的。

只要为会话存储一次凭据,就会为整个TLS会话缓存它们。这导致需要等待大约10分钟,直到该会话消失。

您可以在http://developer.apple.com/library/ios/qa/qa1727/_index.html

了解有关此问题的更多信息

该文件提到了一种有限的解决方法,即附加'。'到服务器名称的末尾。然而,我一直无法做到这一点。

除此之外,这些是我能想到的解决方案:

1)始终使用NSURLCredentialPersistenceNone& connectionShouldUseCredentialStorage应该生成401s的变通方法。自己将基本身份验证标头添加到请求中。这应该可以防止额外的401,同时绕过凭证存储。添加该授权的代码如下所示:

    NSString *s ;
    NSString *authStr ;
    s = [NSString stringWithFormat:@"%@:%@",user,password] ;
    s = [YourBase64Encoder base64EncodingForData:[NSData dataWithBytes:[s UTF8String] length:strlen([s UTF8String])]];
    authStr = [NSString stringWithFormat:@"Basic %@",s] ;        
    [request setValue:authStr forHTTPHeaderField:@"Authorization"] ;

我不知道如何为其他身份验证方法实现这一点,但我认为这是可能的。

2)告知用户该问题并要求他们重新启动应用

3)实现自己的基于http的检索机制的低级套接字,完全绕过CFNetwork。祝你好运:>)

答案 1 :(得分:4)

我刚用AFNetworking遇到了这个问题。我正在使用需要在标头中传递授权的后端。但是,当用户退出应用程序并尝试重新登录时(即使使用不同的信用卡),我从服务器收到错误。我的解决方案是在注销时清除authheader时清除我的应用程序cookie。

- (void)clearAuthorizationHeader {
    [self.manager.requestSerializer clearAuthorizationHeader];
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [storage cookies]) {
        [storage deleteCookie:cookie];
    }
}

答案 2 :(得分:3)

我也遇到过这个问题。清除NSURLCredentialStorage似乎部分有效,但似乎我必须在此之后等待几秒钟才能生效。在不等待的情况下执行另一个HTTP请求会导致使用旧的Authorization标头。

我可以在初始化NSURLCredentialPersistenceNone时传递NSURLCredential来修复它:

NSURLCredential* credentials = [[NSURLCredential alloc] initWithUser:username password:password persistence:NSURLCredentialPersistenceNone];

注意:这会对您使用此NSURLCredential发出的每个HTTP请求导致401质询。但是,如果您找回一些可以让您通过身份验证的cookie,这不是问题。

答案 3 :(得分:1)

对于它的价值,我遇到了同样的问题。

我认为这是一个时间问题。使用模拟器时,如果我在尝试再次登录前等待5-10秒,则登录失败。此外,当我使用实际的手机时,我很少发生问题 - 这可能是手机速度较慢的一个功能,或者可能是模拟器中的错误。

答案 4 :(得分:1)

我知道这是一个古老的话题。然而,对我来说唯一有用的是为不同的证书使用不同的URL。

它在我的应用程序中起作用,因为我只有2个证书(一个是应用程序资源的常规证书,另一个是用户验证过程后从Internet下载的自定义证书)。在我的情况下,没有cookie,也没有要清除的凭据,因此我在stackoverflow上找不到任何解决方案。

答案 5 :(得分:0)

我遇到了同样的问题,现在可以了。

使用NSURLConnection可以通过在网址末尾添加随机数来轻松解决此问题:

因此,请搜索您的URLRequest并将随机数附加到URLRequest

NSInteger randomNumber = arc4random() % 999;
NSString *requestURL = [NSString stringWithFormat:@"%@?cache=%ld",yourURL,(long)randomNumber];

NSURL *URLRequest = [NSURL URLWithString:requestURL];

并确保在您呼叫的所有网址的末尾都有一个随机数。