Кэширование учетных данных URLSession, разрешающее аутентификацию с неверными учетными данными - PullRequest
0 голосов
/ 18 января 2019

Я пытаюсь установить связь с API моей компании в приложении для iOS. Я использую стандартный URLSession.

API автоматически загрузит баланс и перенаправит на другой сервер, поэтому я реализовал методы URLSessionDelegate и URLSessionTaskDelegate, которые обрабатывают перенаправления.

При первом входе в систему я буду перенаправлен с http://our.api.com на http://our1.api.com или другой версии API с другим номером сервера. В первый раз, когда я аутентифицируюсь с http://our1.api.com, он учитывает переданный заголовок авторизации и вызов URLCredential. Но если я попытаюсь снова выполнить аутентификацию на том же API с известными неверными учетными данными, будет использоваться старый URLCredential, и я смогу войти в API, когда не смогу.

Есть ли способ заставить URLSession никогда использовать кэшированный URLCredential или иным образом очистить кэшированные URLCredentials?

Создание URLSession

let config = URLSessionConfiguration.ephemeral
    config.httpAdditionalHeaders = ["Accept":"application/xml",
                                    "Accept-Language":"en",
                                    "Content-Type":"application/xml"]
    config.requestCachePolicy = .reloadIgnoringLocalCacheData
    config.urlCache = nil
    self.urlSession = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)

Обращение к API

var request = URLRequest(url: thePreRedirectedUrl)
    request.httpMethod = "GET"
    request.addValue("Basic username:password", forHTTPHeaderField: "Authorization")

let task = urlSession?.dataTask(with: request, completionHandler: { (data, response, error) in                        
        // pass endpoint results to completion block
        completionBlock(data, response, error)
    })

    // run the task
    if let task = task {
        task.resume()
    }

URLSessionDelegate и URLSessionTaskDelegate

extension ApiManager: URLSessionDelegate, URLSessionTaskDelegate {

func urlSession(_ session: URLSession,
                didReceive challenge: URLAuthenticationChallenge,
                completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

    if challenge.previousFailureCount == 0 {
        completionHandler(.useCredential, URLCredential(user: username, password: password, persistence: .none))

    } else {
        completionHandler(.performDefaultHandling, nil)
    }
}

func urlSession(_ session: URLSession,
                task: URLSessionTask,
                willPerformHTTPRedirection response: HTTPURLResponse,
                newRequest request: URLRequest,
                completionHandler: @escaping (URLRequest?) -> Void) {

        var newRequest = URLRequest(url: request.url!)
        newRequest.addValue("Basic username:password", forHTTPHeaderField: "Authorization")
        newRequest.httpMethod = task.originalRequest?.httpMethod
        newRequest.httpBody = task.originalRequest?.httpBody
        completionHandler(newRequest)
    }
}

1 Ответ

0 голосов
/ 20 января 2019

Самый надежный способ - удалить учетные данные из цепочки для ключей пользователя (macOS) или приложения (iOS).

См. Обновление и удаление элементов цепочки для ключей на веб-сайте Apple для разработчиков, но в основном:

NSDictionary *matchingDictionary = @{
    kSecClass: kSecClassInternetPassword,
    kSecAttrSecurityDomain: @"example.com" // <-- This may not be quite the
                                           //     right format for the domain.
};
SecItemDelete((__bridge CFDictionaryRef) matchingDictionary);
...