2012-02-21 81 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嘗試應答認證挑戰。很可能您的服務器不包含此功能,這就是客戶端未發送憑據的原因。