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

发布于 2024-12-05 08:02:39 字数 2836 浏览 0 评论 0原文

我一直在 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- cookie。网络上还有另一个博客建议向每个 URL 添加“#”以强制重新进行身份验证,这种方法可以工作,但不能解决问题,因为我需要依赖会话的凭据以及使用完全不同的凭据的能力。

这是一个错误还是已知问题,我该如何真正解决这个问题...... 坦率地说:我到底做错了什么?

这确实困扰着我并阻止我继续我的工作。

我将非常感谢任何意见!

多谢!

i've been searching stackoverflow, google, apple and other places. The tips provided look promising, i implemented them but alltogether don't seem to work or get enforced.

Problem: I have an NSURLConnection with specific credentials. I then have a logout where I clear the credentials, the protectionspace, i remove all cached responses and delete all cookies in the sharedHTTPCookieStorage but when calling my authenticated request again a few seconds later even with wrong credentials I still am using the old (deleted) credentials

Here are some code extracts, where credentials are removed

        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];
            }
        }
    }

I then remove all cached responses

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

I then delete all cookies

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

I also tried using no cookies and other policies

    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];

I also tried this hint here on specifically storing the cookies and passing them again. http://www.hanspinckaers.com/multiple-nsurlrequests-with-different-cookies. There's another blog on the web suggesting to add a "#" to each URL in order to enforce reauthentication, which works but just does not solve the issue because I need to count on session's credentials and the ability to use totally different credentials.

Is this a bug or known issue and how do I really solve this...
Put bluntly: What am I exactly doing wrong here?

This is really bugging me and keeping me from continuing my work.

I would greatly appreciate any input!

Thanks alot!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

孤独患者 2024-12-12 08:02:39

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

您可以使用 NSURLCredentialPersistenceNone 或 # 技巧,也可以定义“connectionShouldUseCredentialStorage”委托方法以返回 NO。如果您每次都这样做,并且您的应用程序从不保留会话的凭据,那么这将迫使每个请求都发生质询。

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

对于发送大量请求的应用程序,这些解决方案都会对每个请求生成 401 响应,并且额外的质询响应会增加数据和性能。

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

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

您可以在以下位置阅读有关此问题的更多信息:http://developer.apple。 com/library/ios/qa/qa1727/_index.html

该文档提到了一种有限的解决方法,其中涉及附加“.”。到服务器名称的末尾。然而,我一直无法让它发挥作用。

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

1)始终使用 NSURLCredentialPersistenceNone 和 NSURLCredentialPersistenceNone 。应生成 401 的 connectionShouldUseCredentialStorage 解决方法。自行将基本身份验证标头添加到请求中。这应该可以防止额外的 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。祝你好运:>)

Unfortunately, there does not seem to be a solution to this problem.

You can use NSURLCredentialPersistenceNone or the # trick or you can define the 'connectionShouldUseCredentialStorage' delegate method to return NO. If you do that every time and your app never persists the credentials for a session, that will force the challenge to occur on every request.

For apps that are only performing minimal requests or that end up using a session cookie for authentication, that might work OK.

For apps that are sending a large number of requests, these solutions all result in a 401 response for every single request and that extra challenge-response can add up in terms of data and performance.

It would be nice if you could persist the credential storage for the session until you needed to log out and then switch to one of the work-arounds, but that is not possible.

As soon as you store the credentials once for a session, they get cached for the entire TLS session. That results in a need to wait about 10 minutes until that session goes away.

You can read more about this issue at: http://developer.apple.com/library/ios/qa/qa1727/_index.html

That document mentions a limited work-around that involves appending a '.' to the end of the server name. I have been unable to get that working, however.

Other than that, these are the solutions I can think of:

1) Always use the NSURLCredentialPersistenceNone & connectionShouldUseCredentialStorage workaround that should generate the 401s. Add the Basic authentication header to the request, yourself. This should prevent the extra 401's while also bypassing the credential storage. The code for adding that authorization looks something like this:

    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"] ;

I don't know how this would be implemented for other authentication methods, but I presume it is possible.

2) Inform the user of the issue and ask them to restart the app

3) Implement your own low-level sockets based http retrieval mechanism that bypasses CFNetwork completely. Good luck with that :>)

乖乖哒 2024-12-12 08:02:39

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

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

I just ran into this issue with AFNetworking. I'm working with a backend that requires Authorization to be passed in the header. However, when the user logs out of the app and attempts to log back in (even with different creds) I was getting an error from the server. My solution was to clear out my apps cookies when clearing the authheader in logout.

- (void)clearAuthorizationHeader {
    [self.manager.requestSerializer clearAuthorizationHeader];
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [storage cookies]) {
        [storage deleteCookie:cookie];
    }
}
情释 2024-12-12 08:02:39

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

我能够通过在初始化 NSURLCredential 时传递 NSURLCredentialPersistenceNone 来修复此问题:

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

注意:这将导致您使用此 NSURLCredential 发出的每个 HTTP 请求出现 401 挑战>。但是,如果您取回一些可让您进行身份验证的 cookie,那么这不是问题。

I've run into this issue too. Clearing NSURLCredentialStorage seems to partially work, but it seems like I have to wait a few seconds after this for it to take effect. Doing another HTTP request without waiting results in the old Authorization header being used.

I was able to fix it by passing NSURLCredentialPersistenceNone while initializing my NSURLCredential:

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

note: this will cause 401 Challenges on every HTTP request you make with this NSURLCredential. However this isn't an issue if you get back some cookies that keep you authenticated.

若无相欠,怎会相见 2024-12-12 08:02:39

就其价值而言,我也遇到了同样的问题。

我认为这是一个时间问题。使用模拟器时,如果我等待 5-10 秒再尝试再次登录,则会按预期登录失败。另外,当我使用实际的手机时,我很少会出现这个问题 - 这可能是手机速度较慢的原因,或者可能是模拟器中的错误。

For what it's worth, I'm having the same problem.

I think it's a timing issue. When using the simulator, if I wait 5-10 seconds before trying to log in again, login fails as expected. Also, when I use an actual phone, I can rarely get the problem to occur - which might be a function of the phone being slower, or might be a bug in the simulator.

栖迟 2024-12-12 08:02:39

我知道这是一个老话题了。然而,唯一对我有用的是对不同的证书使用不同的网址。

它在我的应用程序中有效,因为我只有 2 个证书(一个在应用程序资源中通用,一个在用户验证过程后从互联网下载的自定义证书)。就我而言,没有 cookie,也没有需要清除的凭据,因此我在 stackoverflow 上找到的解决方案都不起作用。

I know it's an old topic. However the only thing, that works for me was to use different urls for different certificates.

It worked in my application, since I have only 2 certificates (one general in application resources and one custom downloaded from internet after the user verification process). In my case there are no cookies, and no credentials to clear so none of the solutions I found on stackoverflow worked.

相思故 2024-12-12 08:02:39

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

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

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

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

NSURL *URLRequest = [NSURL URLWithString:requestURL];

并确保您调用的所有 URL 末尾都有一个随机数。

I was facing the same problem, now it works.

Using NSURLConnection this issue can be fixed easily by adding a random number to the end of the URL:

So, search for your URLRequest and append the random number to URLRequest

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

NSURL *URLRequest = [NSURL URLWithString:requestURL];

And make sure you have a random number at the end of all URLs you are calling.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文