2012-02-21 82 views
4

我正在尝试使用NSURLConnection连接到http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/。此演示Web服务是documented要求身份验证(登录:管理员/密码:管理员)。NSURLConnection不使用默认凭证

编辑:此Web服务现在发送身份验证质询,但当时并未提出问题。

此Web服务发送一个验证挑战,所以我不能用connection:didReceiveAuthenticationChallenge:委托方法。相反,我在共享凭据存储中设置了默认的NSURLCredential。不幸的是,这个默认凭证不被NSURLConnection使用。

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

@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(登录页)而不是XML。如果我将manuallyAddAuthorizationHeader变量设置为YES,那么授权将起作用,并且我会收到xml。

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

回答

8

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

如果您需要主动发送凭证,那么您必须自己手动添加标题。你可以只基于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复制,虽然我已经写了类似的代码,自己很多次。)

3

由于HTTP支持多种不同的身份验证方法(基本,简要,Kerberos的,等等),前NSURLConnection不能发送的凭据它收到来自服务器的验证质询,因为它不知道如何发送它们。

+0

我使用'authenticationMethod:NSURLAuthenticationMethodHTTPBasic'显式创建了一个'NSURLProtectionSpace',所以我想现在要使用什么方法。 – 0xced 2012-02-21 18:03:07

0

虽然BJ的答案可能会解决您在客户端的问题,但真正的问题是服务器。 内部NSURLConnection将使用它自己的等效委托方法connection:didReceiveAuthenticationChallenge:和其他验证方法。这是它可以从NSURLCredentialStorage申请凭据的地方。在你的情况下,这似乎并没有发生。对于那些要调用的方法,服务器不仅要提供40x HTTP状态码,还必须包含WWW-Authenticate标头。这告诉NSURLConnection尝试应答认证挑战。很可能您的服务器不包含此功能,这就是客户端未发送凭据的原因。