3

我正在尝试在我的 iOS 应用程序中与我公司的 API 进行通信。我正在使用标准的 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)
    }
}
4

1 回答 1

0

最可靠的方法是从用户 (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);
于 2019-01-20T04:52:27.200 回答