Использование дайджест-аутентификации HTTP на iPhone
У меня есть приложение, которое взаимодействует с сервером, использующим дайджест-аутентификацию HTTP.
Мне кажется, что управление " сессией "в iPhone довольно" черный ящик " для нас, разработчиков. Правда ли, что мы не видим, как платформа обрабатывает / сохраняет сеансы http?
Если я просто тусклый здесь, кто-нибудь потрудится объяснить, как, вероятно, обрабатывать аутентификацию http Digest на iPhone?
мой основной прогон есть:
- сделайте запрос на защищенный url
- сервер отправляет 401
- клиент создает и сохраняет учетные данные и передает их обратно на сервер
- сервер проверяет учетные данные, завершает запрос, если проверено, отправляет еще 401, если нет.
- сделайте последующий запрос для защиты url
- сервер снова запрашивает авторизацию........
Это работает для отдельных запросов, но если я сделаю дополнительные, последующие запросы, сервер запрашивает авторизацию снова. Сервер сохранил сеанс для конкретного пользователя, но iPhone по какой-то причине не делает запрос в том же сеансе... Поэтому сервер должен выбрасывать объект аутентификации и создавать новый каждый раз, когда клиент делает запрос на защищенный url-адрес.
Я уверен, что это неправильное поведение.
Если мы посмотрим, как ведет себя браузер в этом ситуация:
- браузер запрашивает данные из безопасного url
- сервер отправляет 401
- браузер запрашивает у пользователя учетные данные, сохраняет их, передает на сервер
- сервер проверяет учетные данные, возвращает данные, если они проверены, отправляет еще 401, если нет.
- последующие запросы для защиты URL-адресов не запрашиваются учетные данные, поскольку браузер управляет сеансом.
Я создаю NSURLCredential и сохранение его в NSURLCrendtialStorage. Затем, когда приложение получает "didReceiveAuthenticationChallenge", я извлекаю учетные данные из хранилища и передаю их обратно, создавая учетные данные, если они не существуют (по первому запросу).
любая помощь была бы весьма признательна. Спасибо.
2 ответов
Первое, что нужно забыть о сеансах HTTP, так как они не взаимодействуют с активными логинами дайджест-аутентификации (есть своего рода информация о сеансе, но это другое).
действительно, одна из основных причин использования Digest-не использовать сеансы только для поддержания состояния входа в систему. Сеансы тяжелые и повреждают масштабируемость.
Я не мог сказать наверняка, в чем ваша проблема, но я знаю, что я бы проверил сначала, что является правильным использованием устаревшего и правильное создание nonces.
User-агенты могут обрабатывать аутентификацию только без запроса пользователя, если их попросят обработать тот же nonce, или в другом случае я приду позже (проще объяснить это в этом порядке).
Если у вас есть тот же nonce, используемый в каждом запросе, то user-agent будет продолжать использовать его вместе с "ha1" от пользователя/pass для запроса последующих ресурсов. Это делается preëmptively, поэтому задача не происходит.
конечно, использование того же nonce вводит элемент небезопасности, поскольку атаки воспроизведения становятся тривиальными для любого, кто может нюхать трафик. Идиотов придется менять на регулярной основе.
следовательно, если вы получаете запрос от user-agent с недопустимым заголовком авторизации, но причина этого недопустима в том, что nonce неверен (он использует истекший), то в ваш вызов включите "stale=true" (по умолчанию false). Об этом сообщает user-agent то, что ваша причина для отклонения-это nonce, устарело (конечно, другая информация также может быть неправильной, но это не имеет значения, поскольку вы не собираетесь позволять ей играть в любом случае).
при получении такого устаревшего=true пользовательский агент будет знать, что он не авторизован, но вместо запроса пользователя (или создания исключения, если это компонент без пользовательского интерфейса) повторит старые критерии с новым nonce.
Я не могу сказать, если это то, что влияет на вас, но nonces и staleness определены и сигнализированы, безусловно, первое, на что я бы посмотрел.
Я написал приложение для iPhone с HTTP-аутентификацией и испытал то, что вы описываете. (Мое приложение использует базовую аутентификацию вместо дайджест-аутентификации,но это не имеет большого значения.)
причина проблемы находится на стороне iPhone. Сервер должен ответить 401, если iPhone не отправляет учетные данные в заголовке HTTP-запроса. И на самом деле это не так, хотя это легко может быть, как только учетные данные хранятся в учетных данных место хранения.
Это странное поведение оказало серьезное влияние на скорость приложения, так как каждый запрос вызывал два раунда на сервер вместо одного (первый со статусом 401, второй с 200).
Я решил это, вручную установив учетные данные в заголовке HTTP-запроса:
NSString* credentials = [NSString stringWithFormat: @"%@:%@", usr, pwd];
const char* credentialsChars = [credentials cStringUsingEncoding: NSUTF8StringEncoding];
credentials = [CommunicationUtil stringBase64WithData: (const UInt8*) credentialsChars length: strlen(credentialsChars)];
NSString* authorizationHeader = [NSString stringWithFormat: @"Basic %@", credentials];
NSMutableURLRequest* request =
[[NSMutableURLRequest alloc] initWithURL: url
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval: 15];
[request setValue: authorizationHeader forHTTPHeaderField: @"Authorization"];
теперь мое приложение работает очень плавно и очень отзывчивый.
решение будет выглядеть немного иначе для дайджест-аутентификации. Но вы поймете идею.