NSURLConnection не использует учетные данные по умолчанию - PullRequest
4 голосов
/ 21 февраля 2012

Я пытаюсь подключиться к http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ с помощью NSURLConnection.Этот демонстрационный веб-сервис задокументирован , требующий аутентификации (логин: администратор / пароль: администратор).

Редактировать : этот веб-сервис теперь отправляет запрос аутентификации, это не было в то время, когда вопрос задавался.

Этот веб-сервис не отправляет запрос аутентификации, поэтому я не могу использовать метод делегата 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

Ответы [ 3 ]

8 голосов
/ 21 февраля 2012

Отправка учетных данных по умолчанию без проверки подлинности считается небезопасной, особенно в случае, когда вы общаетесь по обычному HTTP. Спецификация HTTP гласит, что вы можете отправлять учетные данные с упреждением, но обычно вам следует подождать проверки подлинности. И это поведение, которое Какао обеспечивает по умолчанию.

Если вам нужно предварительно отправить учетные данные, вам придется вручную добавить заголовки. Вы можете просто закодировать его с помощью 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 в качестве заголовка Authorization в вашем NSURLRequest.

(Код явно скопирован с https://stackoverflow.com/a/509480/100478,, хотя я сам много раз писал подобный код.)

3 голосов
/ 21 февраля 2012

Поскольку HTTP поддерживает множество различных методов аутентификации (Basic, Digest, Kerberos и т. Д.), NSURLConnection не может отправить учетные данные, пока не получит запрос аутентификации от сервера, поскольку не знает, как их отправить.

0 голосов
/ 25 июля 2013

Хотя ответ BJ может решить вашу проблему на стороне клиента, реальная проблема - это сервер.Внутренне NSURLConnection будет использовать свой собственный эквивалент метода делегата connection:didReceiveAuthenticationChallenge: и других методов аутентификации.Здесь он ищет учетные данные, которые он может применить с NSURLCredentialStorage.В вашем случае, похоже, этого не происходит.Для того, чтобы эти методы были вызваны, сервер должен не только предоставить 40-кратный код состояния HTTP, но он также должен содержать заголовок WWW-Authenticate.Это говорит NSURLConnection, чтобы попытаться ответить на запрос аутентификации.Вероятно, ваш сервер не включает это, и поэтому клиент не отправляет учетные данные.

...