Подтвердить что ты не робот

Могу ли я использовать NSURLCredentialStorage для базовой аутентификации HTTP?

У меня есть класс cocoa, который я хочу использовать для подключения к веб-службе 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 или любого из классов проверки подлинности. Кроме того, есть ли какие-либо ресурсы, где я могу больше узнать о классах cocoa Authentication?

Спасибо.

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

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

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

4b9b3361

Ответ 1

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

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

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

NSURLRequest *request =
  [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://user:[email protected]"]];

[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];

Ответ 2

В ситуации, когда ошибка 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 (для Например, вместо этого он отправляет обычную страницу).

Ответ 3

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

Ответ 4

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

// 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, которое оспаривается с использованием защитного пространства, которое соответствует установленному вами, будет использовать этот учетный параметр