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
设置为NSURLRequest
的Authorization
标头即可。
(代码复制公然从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挑战。 您的服务器很可能不包括这个,这就是客户端没有发送证书的原因。