URLSession凭据缓存允许使用不正确的凭据进行身份验证

时间:2019-01-17 22:19:07

标签: ios swift urlsession nsurlcredential nsurlcredentialstorage

我正在尝试在我的iOS应用中与公司的API通信。我正在使用标准的URLSession。

API将自动进行负载平衡并重定向到其他服务器,因此我已经实现了用于处理重定向的URLSessionDelegate和URLSessionTaskDelegate方法。

最初登录时,我将从http://our.api.com重定向到http://our1.api.com或其他版本的具有不同服务器编号的API。我第一次使用http://our1.api.com进行身份验证时,它将尊重传入的Authorization标头和质询的URLCredential。但是,如果我尝试使用已知的错误凭据再次针对相同的API进行身份验证,则会使用旧的URLCredential,并且在无法访问API时可以进入该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 :(得分:0)

最可靠的方法是从用户(macOS)或应用程序(iOS)的钥匙串中删除凭据。

有关详情,请参阅Apple开发者网站上的Updating and Deleting Keychain Items,但基本上:

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