Как изменить учетные данные для NSURLSession
У меня следующая проблема: я делаю запросы к серверу, который использует HTTP-аутентификацию и дает мне
- 401, если я не отправляю аутентификацию
- 401, если я отправлю неверную аутентификацию
- a 403, если я отправлю действительную аутентификацию, но ресурс для этого пользователя запрещен.
Когда я получаю 401, моя NSURLSession достаточно дружелюбна, чтобы вызвать своего делегата через
URLSession(
session: NSURLSession,
task: NSURLSessionTask, didReceiveChallenge
challenge: NSURLAuthenticationChallenge,
completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void)
где я могу изменить учетные данные, отправляемые на сервер.
Однако при получении 403 я сталкиваюсь с проблемой. Оттуда я не могу заставить сеанс использовать какие-либо другие учетные данные, кроме тех, что он использовал для получения 403. На 403 делегат не спрашивается (это нормально, это не 401), так как я могу контролировать, какие учетные данные отправлено в будущем для этой защиты пространства? Даже ручная очистка общего NSURLCredentialStorage и / или установка там правильных учетных данных напрямую не помогает:
let credential = NSURLCredential(user: username, password: password, persistence: .ForSession)
let protectionSpace = NSURLProtectionSpace(
host: self.host,
port: self.apiRootURL.port!.integerValue,
protocol: self.apiRootURL.scheme!,
realm: "MyRealm",
authenticationMethod: NSURLAuthenticationMethodHTTPBasic)
NSURLCredentialStorage.sharedCredentialStorage().setDefaultCredential(credential, forProtectionSpace: protectionSpace)
После этого вызова правильные учетные данные - единственные, перечисленные в NSURLCredentialStorage - но следующий вызов к серверу все еще будет включать старые учетные данные, которые неизбежно приведут к другим 403.
Даже сбросив сеанс, используя его reset(completionHandler: @escaping () -> Void)
метод не помогает.
TLDR; как я могу изменить учетные данные, которые NSURLSession продолжает использовать, как только он имел успех с ними для данного домена защиты?
1 ответ
Вы ловите ответное сообщение 403, затем либо
- Выполните запрос URL-адреса для выхода, затем URL-адреса для входа.
- Всегда предотвращайте сохранение учетных данных в хранилище учетных данных, чтобы вы всегда получали обратный вызов.
- Удалите существующие учетные данные после 403, чтобы вызвать обратный вызов.
Я рекомендую второй или третий подход, в зависимости от которого в среднем получается меньше запросов. Чтобы избежать персистентности, передайте NSURLCredentialPersistenceNone или эквивалент Swift вместо того, чтобы указывать ему сохраняться в течение сеанса. Чтобы удалить учетные данные, позвоните removeCredential:forProtectionSpace:options:
,
Есть несколько других возможностей, которые могут работать, в зависимости от дизайна вашего приложения и дизайна сервера:
- Предварительно добавьте правильные учетные данные в связку ключей / хранилище учетных данных. Предостережение: есть только одна цепочка для ключей, поддерживающая его, так что это не очень хороший подход, если у вас есть несколько одновременных запросов, которые должны приходить от разных учетных записей, потому что вы не будете иметь большого контроля над тем, какие учетные данные отправляются для данного запроса.
- Используйте другую область аутентификации для вещей, которые требуют аутентификации от имени другого пользователя.