Могу ли я использовать NSURLCredentialStorage для базовой аутентификации HTTP? - PullRequest
19 голосов
/ 01 февраля 2009

У меня настроен класс какао, который я хочу использовать для подключения к веб-сервису RESTful, который я создаю. Я решил использовать базовую аутентификацию HTTP на своем бэкэнде PHP следующим образом ...

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    //Stuff that users will see if they click 'Cancel'
    exit;
}
else {
    //Validation Code
    echo "You entered info.";
}
?>

На данный момент я использую синхронную NSURLConnection, которая, как я понимаю, в документации Apple содержит меньше поддержки для аутентификации.

Но возможно ли это вообще? Я могу очень легко выполнить проверку подлинности с помощью файлов cookie без NSURLProtectionSpaces или NSURLCredentials или любого из классов проверки подлинности. Кроме того, есть ли ресурсы, где я могу прочитать больше о классах аутентификации Какао?

Спасибо.

ОБНОВЛЕНИЕ: mikeabdullahuk Код, который вы предоставили (второй пример), практически идентичен тому, что я написал. Я провел еще несколько расследований и обнаружил, что NSURLConnection возвращает ошибку ...

Error Domain=NSURLErrorDomain Code=-1012 UserInfo=0x1a5170 "Operation could not be completed. (NSURLErrorDomain error -1012.)"

Код соответствует NSURLErrorUserCancelledAuthentication. Так что, очевидно, мой код не обращается к NSURLCredentialStorage, а вместо этого отменяет аутентификацию. Может ли это иметь какое-либо отношение к функциям PHP HTTP-аутентификации? Я совершенно сбит с толку.

Ответы [ 4 ]

62 голосов
/ 02 февраля 2009

Синхронный NSURLConnection будет абсолютно работать с NSURLCredentialStorage. Вот как все обычно работает:

  1. NSURLConnection запрашивает страницу с сервера
  2. Сервер отвечает 401 ответом
  3. NSURLConnection проверяет, какие учетные данные он может получить из URL
  4. Если URL не предоставил полные учетные данные (имя пользователя и пароль), NSURLConnection также свяжется с NSURLCredentialStorage, чтобы заполнить пробелы
  5. Если для полных учетных данных все еще не определено, NSURLConnection отправит -connection:didReceiveAuthenticationChallenge: метод делегата с запросом учетных данных
  6. Если NSURLConnection теперь наконец имеет полные учетные данные, он повторяет исходный запрос, включая данные авторизации.

Используя метод синхронного подключения, вы только теряете на шаге 5 возможность обеспечить пользовательскую аутентификацию. Таким образом, вы можете либо предварительно предоставить учетные данные для аутентификации в URL-адресе, либо поместить их в NSURLCredentialStorage перед отправкой запроса. например, * * тысяча тридцать три

NSURLRequest *request =
  [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://user:pass@example.com"]];

[NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];

или

NSURLCredential *credential = [NSURLCredential credentialWithUser:@"user"
                                                         password:@"pass"
                                                      persistence:NSURLCredentialPersistenceForSession];

NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
  initWithHost:@"example.com"
  port:0
  protocol:@"http"
  realm:nil
  authenticationMethod:nil];


[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential
                                                    forProtectionSpace:protectionSpace];
[protectionSpace release];

NSURLRequest *request =
  [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]];

[NSURLConnection sendSynchronousRequest:request returningResponse:NULL error:NULL];
12 голосов
/ 04 февраля 2009

В ситуации, когда проверка подлинности 401 или другая проверка подлинности неприемлема / невозможна, я иногда использую фиктивное сообщение CFHTTPMessage для генерации строки аутентификации, а затем копирую ее обратно в NSURLRequest:

// assume NSString *username and *password exist and NSURLRequest *urlRequest
// exists and is fully configured except for HTTP Basic Authentication.. 

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);

[urlRequest setValue:authorizationString forHTTPHeaderField:@"Authorization"];

Это может показаться совершенно странным способом сделать это, но терпимо к ситуациям, когда имя пользователя / пароль не являются чистыми в URL, и где NSURLRequest отказывается обращаться к NSURLCredentialStorage, потому что сервер фактически не отправляет HTTP 401 (для Например, вместо этого отправляется обычная страница.

0 голосов
/ 14 февраля 2013

Установите свои учетные данные в качестве учетных данных по умолчанию для пространства защиты:

// Permananent, session, whatever.
NSURLCredential *credential = [NSURLCredential credentialWithUser:username password:password persistence: NSURLCredentialPersistencePermanent];
// Make sure that if the server you are accessing presents a realm, you set it here.
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:@"blah.com" port:0 protocol:@"http" realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic];
// Store it
[[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace];

На этом этапе любое последующее NSURLConnection, которое оспаривается с использованием пространства защиты, которое совпадает с тем, которое вы установили, будет использовать эти учетные данные

0 голосов
/ 02 февраля 2009

Я хотел бы отметить, что ответ mikeabdullahuk хорош, но также если вы используете NSURLCredentialPersistencePermanent вместо сеанса, он будет хранить учетные данные в цепочке ключей пользователей, поэтому в следующий раз вы сможете проверить NSURLCredentialStorage на значение, отличное от nil, для учетных данных по умолчанию для пространства защиты и если вы получите значение, отличное от nil, вы можете просто передать учетные данные. Я сейчас использую этот метод для клиента Delicious.com, который я пишу, и он очень хорошо работает в моих тестах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...