NSURLSession с пользовательской аутентификацией?

Наше приложение использует вызовы службы RESTful с использованием NSURLSession. Сами вызовы маршрутизируются через обратный прокси-сервер, чтобы помочь в управлении сеансом, безопасности и т. Д. На сервере. Единственная проблема, с которой мы сталкиваемся, связана с аутентификацией. Когда пользователь пытается получить доступ к защищенному ресурсу - либо через браузер, либо через вызов REST - и он не аутентифицирован, обратный прокси-сервер отображает страницу входа в HTML.

Проблема в том, что мы хотели бы использовать способность NSURLSession автоматически обрабатывать проблемы аутентификации. Однако NSURLSession не может распознать, что мы получаем ответ на запрос аутентификации, потому что клиенту не возвращается HTTP 401 или другой код ошибки. Обратный прокси-сервер отправляет 200, потому что HTML был успешно доставлен. Мы можем распознать, что это страница входа в систему, проверив HTML-код в клиенте, но мы хотели бы иметь возможность обрабатывать аутентификацию с использованием пользовательского NSURLAuthenticationChallenge, если это вообще возможно, чтобы NSURLSession мог повторять запросы после аутентификации. успешно.

Есть ли способ узнать, что мы возвращаем страницу входа в наш completionHandler, и сообщить NSURLSession, что мы действительно получаем ответ на запрос аутентификации? Или NSURLSession требует, чтобы мы получили обратно код ошибки HTTP (401 и т. Д.)


person Shadowman    schedule 06.08.2014    source источник
comment
Помимо отрицательного ответа ниже, вы нашли способ получить NSURLAuthenticationChallenge для вашей ситуации? Есть ли хорошие решения для ситуации?   -  person Sunny    schedule 09.02.2015


Ответы (4)


Проблемы аутентификации инициируются заголовком WWW-Authenticate в ответе 40x.

Из документации:

Системные классы загрузки URL не вызывают своих делегатов для обработки запросов запросов, если ответ сервера не содержит заголовок WWW-Authenticate. Для других типов проверки подлинности, таких как проверка подлинности прокси и проверка доверия TLS, этот заголовок не требуется.

К сожалению, вышеупомянутая прокси-аутентификация не применяется в вашем сценарии обратного прокси / ускорителя.

person quellish    schedule 15.08.2014

На ум приходит пара возможностей.

  1. Если вы используете представление NSURLSession делегатом, вы можете обнаружить перенаправление на страницу сбоя аутентификации с помощью NSURLSessionTaskDelegate метода willPerformHTTPRedirection.

    Вероятно, вы также можете обнаружить перенаправление, проверив currentRequest.URL задачи и увидев, произошло ли перенаправление и там. Как говорится в документации, currentRequest «обычно совпадает с исходным запросом (originalRequest), за исключением случаев, когда сервер ответил на первоначальный запрос перенаправлением на другой URL-адрес».

  2. Предполагая, что служба RESTful обычно не возвращает HTML, вы можете посмотреть NSURLResponse, подтвердить, что это действительно подкласс NSHTTPURLResponse, а затем посмотреть allHeaderFields, чтобы убедиться, что text/html появляется в Content-Type ответа. Это, очевидно, работает только в том случае, если страница аутентификации возвращает Content-Type, который включает text/html, а остальные ваши ответы - нет (например, они application/json или что-то в этом роде).

    Во всяком случае, это может выглядеть так:

    NSString *contentType = [self headerValueForKey:@"Content-Type" response:response];
    
    if ([contentType rangeOfString:@"text/html"].location != NSNotFound) {
        // handle it here
    }
    

    Где headerValueForKey может быть определено следующим образом:

    - (NSString *)headerValueForKey:(NSString *)searchKey response:(NSURLResponse *)response
    {
        if (![response isKindOfClass:[NSHTTPURLResponse class]])
            return nil;
    
        NSDictionary *headers = [(NSHTTPURLResponse *) response allHeaderFields];
    
        for (NSString *key in headers) {
            if ([searchKey caseInsensitiveCompare:key] == NSOrderedSame) {
                return headers[key];
            }
        };
    
        return nil;
    }
    
  3. В худшем случае вы можете обнаружить ответ HTML и проанализировать его, используя что-то вроде HPPLE, и программно обнаружить ответ HTML аутентификации.

    См. Статью Вендерлиха Как разбирать HTML на iOS.

Честно говоря, я бы предпочел видеть ответ REST, чтобы сообщить об ошибке аутентификации с ответом REST (или правильным запросом на сбой аутентификации или ответом, отличным от 200), а не перенаправлением на страницу HTML. Если у вас есть возможность изменить ответ сервера, это будет мое личное предпочтение.

person Rob    schedule 13.08.2014

Вы пробовали просто установить имя пользователя и пароль для заголовка авторизации NSMutableURLRequest как такового.

NSString *authorizationString = [[[NSString stringWithFormat:@"%@:%@",user, password] dataUsingEncoding:NSUTF8StringEncoding] base64Encoding]; 

[yourRequest setValue:[NSString stringWithFormat:@"Basic %@", authorizationString] forHTTPHeaderField:@"Authorization"];

Это должно сработать.

person davetw12    schedule 06.08.2014
comment
Если бы вы прочитали вопрос, вы бы увидели, что я не выполняю обычную или дайджест-аутентификацию. Скорее я использую аутентификацию на основе HTML-форм. Если бы я выполнял обычную проверку подлинности, я бы получил ответ 401 и смог бы легко на него ответить. Однако я получаю 200, потому что HTML-код страницы входа был успешно возвращен. В этом корень проблемы. - person Shadowman; 07.08.2014
comment
Я это понимаю. Этот ответ для тех случаев, когда вы вернетесь 200. - person davetw12; 07.08.2014
comment
Вы ведь не просто говорите о публикации в HTML-форме, верно? Потому что, если бы это было так, не нужно было бы настраивать nsurlauthentication. Вы просто разместите свое имя пользователя и пароль на страницах, где это необходимо. - person davetw12; 07.08.2014
comment
Да, я говорю о простом POST. Однако выполнение этого вручную внутри задачи приведет к тому, что мы потеряем преимущество воспроизведения задачи, предоставляемое NSURLSession. Если бы мы использовали обычную аутентификацию, NSURLSession распознал бы запрос аутентификации и затем воспроизвел бы задачу, когда аутентификация была успешной. Мы потеряем это, если вручную обнаружим страницу входа и выполним POST вручную. Мой вопрос: можем ли мы распознать страницу входа, а затем заставить NSURLSession распознать это как проблему аутентификации? - person Shadowman; 07.08.2014

Вы можете попробовать использовать библиотеку парсера HTML (например, https://github.com/nolanw/HTMLReader).

Затем в блоке обработчика завершения вы можете оценить ответ, чтобы проверить, является ли это HTML-страницей и содержит ли она форму входа.

Я не знаю эту библиотеку, но думаю, вы можете использовать ее так:

HTMLDocument *document = [HTMLDocument documentWithString:responseObjectFromServer];
HTMLNode *node = [document firstNodeMatchingSelector:@"form.login"];
if(node) {
    // Perform second NSURLSession call with login data
}
person matt.P    schedule 13.08.2014