在Foundation的documentation for Swift's URLRequest中,它说不应为保留的HTTP标头使用设置URLRequest标头值的标准方法。
在文档中指向the list of reserved HTTP headers的链接稍深一些时,它表示可能会忽略设置这些标头的尝试。
但是它也说Authorization
是保留的HTTP标头。
这不对,对吗? Universe中的很大一部分API要求您以Authorization: Bearer {token}
因此,如果Swift不允许您设置Authorization
标头,那么一个人如何访问这些API之一?
答案 0 :(得分:0)
实施身份验证挑战以处理基本身份验证,例如:
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
switch challenge.protectionSpace.authenticationMethod {
case NSURLAuthenticationMethodHTTPBasic:
performBasicAuthentication(challenge: challenge, completionHandler: completionHandler)
default:
completionHandler(.performDefaultHandling, nil)
}
}
func performBasicAuthentication(challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let credential = URLCredential(user: "username", password: "password", persistence: .forSession)
completionHandler(.useCredential, credential)
}
这里是参考文献link
答案 1 :(得分:0)
按照你们所有人提到的文档,我现在结束了以下内容:
class ApiManager: NSObject {
var credential: URLCredential?
func token(withCredential credential: URLCredential?) {
guard let url = URL(string: "\(K.API)/token") else {
print("error URL: \(K.API)/token")
return
}
self.credential = credential
let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "accept")
request.setValue("application/json", forHTTPHeaderField: "content-type")
let task = session.dataTask(with: request) { (data, response, error) in
self.credential = nil
if error != nil {
print("URLSession error: \(error!.localizedDescription)")
return
}
guard let safeHttpResponse = response as? HTTPURLResponse else {
print("HTTPURLResponse error: \(error!.localizedDescription)")
return
}
if safeHttpResponse.statusCode == 200,
let safeData = data,
let dataString = String(data: safeData, encoding: .utf8) {
print("safeData: \(dataString)")
} else {
print("error: \(safeHttpResponse.statusCode)")
}
}
task.resume()
}
}
这里,token
是一种方法,作为对用户进行身份验证的示例。
我将类似的东西从 UI 传递给这个方法
URLCredential(user: usernameTextField.text, password: passwordTextField.text, persistence: .forSession)
那么最重要的是URLSessionTaskDelegate
extension ApiManager: URLSessionTaskDelegate {
// From https://developer.apple.com/forums/thread/68809
// We should use session delegate as setting Authorization Header won't always work
func urlSession(
_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// This method is called mainly with HTTPS url
let protectionSpace = challenge.protectionSpace
let authMethod = protectionSpace.authenticationMethod
guard authMethod == NSURLAuthenticationMethodServerTrust, protectionSpace.host.contains(K.API.host) else {
completionHandler(.performDefaultHandling, nil)
return
}
guard let safeServerTrust = protectionSpace.serverTrust else {
completionHandler(.performDefaultHandling, nil)
return
}
DispatchQueue.global().async {
SecTrustEvaluateAsyncWithError(safeServerTrust, DispatchQueue.global()) { (trust, result, error) in
if result {
completionHandler(.useCredential, URLCredential(trust: trust))
} else {
print("Trust failed: \(error!.localizedDescription)")
completionHandler(.performDefaultHandling, nil)
}
}
}
}
func urlSession(
_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// This method is called for authentication
let protectionSpace = challenge.protectionSpace
let authMethod = protectionSpace.authenticationMethod
switch (authMethod, protectionSpace.host) {
case (NSURLAuthenticationMethodHTTPBasic, K.API.host):
self.basicAuth(didReceive: challenge, completionHandler: completionHandler)
// we could add other authentication e.g Digest
default:
completionHandler(.performDefaultHandling, nil)
}
}
private func basicAuth(
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.previousFailureCount < 3 {
completionHandler(.useCredential, self.credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
我这样称呼一切:
let apiManager = ApiManager()
let credential = URLCredential(user: email, password: password, persistence: .forSession)
apiManager.token(withCredential: credential)
例如,我必须使用 completionHandler 处理响应,但请求已通过身份验证且有效