NSURLConnection不使用默认凭证

我正尝试使用NSURLConnection连接到http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ 。 此演示Web服务被logging为需要身份validation(login:pipe理员/密码:pipe理员)。

编辑 :这个Web服务现在发送一个身份validation的挑战,它不是在问的时候被问到。

此Web服务发送身份validation质询,因此我无法使用connection:didReceiveAuthenticationChallenge:委托方法。 相反,我在共享凭据存储中设置了默认NSURLCredential 。 不幸的是, NSURLConnection没有使用这个默认凭证。

这里是我的代码(使用ARC,在iOS 5上testing):

 @implementation ViewController { NSMutableData *responseData; } - (IBAction) connect:(id)sender { NSString *user = @"Administrator"; NSString *password = @"Administrator"; NSURL *nuxeoURL = [NSURL URLWithString:@"http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/"]; NSURLCredential *credential = [NSURLCredential credentialWithUser:user password:password persistence:NSURLCredentialPersistenceForSession]; NSString *host = [nuxeoURL host]; NSNumber *port = [nuxeoURL port]; NSString *protocol = [nuxeoURL scheme]; NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:host port:[port integerValue] protocol:protocol realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:nuxeoURL]; BOOL manuallyAddAuthorizationHeader = NO; if (manuallyAddAuthorizationHeader) { NSData *authoritazion = [[NSString stringWithFormat:@"%@:%@", user, password] dataUsingEncoding:NSUTF8StringEncoding]; NSString *basic = [NSString stringWithFormat:@"Basic %@", [authoritazion performSelector:@selector(base64Encoding)]]; [request setValue:basic forHTTPHeaderField:@"Authorization"]; } NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; [connection start]; } - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { responseData = [NSMutableData data]; } - (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [responseData appendData:data]; } - (void) connectionDidFinishLoading:(NSURLConnection *)connection { NSLog(@"connectionDidFinishLoading:%@", connection); NSLog(@"%@", [[NSString alloc] initWithData:responseData encoding:NSISOLatin1StringEncoding]); } - (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"connection:%@ didFailWithError:%@", connection, error); } @end 

由于不使用默认凭证,因此我接收到html(login页面)而不是xml。 如果我将manuallyAddAuthorizationHeader授权化variables设置为YES ,那么授权将起作用,并且会收到xml。

我的问题是:为什么NSURLConnection不会自动使用默认的NSURLCredential

在没有authentication质询的情况下发送默认凭证被认为是不安全的,尤其是在通过普通HTTP进行通信的情况下。 HTTP规范说,您可以主动发送凭据,但通常应该等待身份validation的挑战。 这就是Cocoa默认提供的行为。

如果您需要主动发送凭证,则必须自行手动添加标题。 你可以自己编码base-64,或者你可以使用CFHTTP函数为你做这件事情,就像这样:

 CFHTTPMessageRef dummyRequest = CFHTTPMessageCreateRequest( kCFAllocatorDefault, CFSTR("GET"), (CFURLRef)[urlRequest URL], kCFHTTPVersion1_1); CFHTTPMessageAddAuthentication( dummyRequest, nil, (CFStringRef)username, (CFStringRef)password, kCFHTTPAuthenticationSchemeBasic, FALSE); authorizationString = (NSString *)CFHTTPMessageCopyHeaderFieldValue( dummyRequest, CFSTR("Authorization")); CFRelease(dummyRequest); 

然后,只需将authorizationString设置为NSURLRequestAuthorization标头即可。

(代码复制公然从https://stackoverflow.com/a/509480/100478 ,虽然我自己多次写了类似的代码。)

由于HTTP支持许多不同的身份validation方法(基本,摘要,Kerberos等), NSURLConnection在从服务器收到身份validation质询之前无法发送凭据,因为它不知道如何发送它们。

虽然BJ的答案可以解决你的问题在客户端,真正的问题是服务器。 内部NSURLConnection将使用它自己的connection:didReceiveAuthenticationChallenge:方法connection:didReceiveAuthenticationChallenge:的等价物connection:didReceiveAuthenticationChallenge:和其他authentication方法。 这是它可以从NSURLCredentialStorage申请凭据的NSURLCredentialStorage 。 在你的情况下,这似乎并没有发生。 对于那些被调用的方法,服务器不仅要提供一个40x的HTTP状态码,而且必须包含一个WWW-Authenticate头。 这告诉NSURLConnection试图回答authentication挑战。 您的服务器很可能不包括这个,这就是客户端没有发送证书的原因。