Alamofire 5 替代 sessionDidReceiveChallenge
Alamofire 5 alternative to sessionDidReceiveChallenge
我刚换到 Alamofire 5。
之前我使用了 URLSession 和 Certificate Pinner 并且为了处理身份验证挑战我使用了 URLSessionDelegate
的委托方法和散列值
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
print("being challanged! for \(challenge.protectionSpace.host)")
guard let trust = challenge.protectionSpace.serverTrust else {
print("invalid trust!")
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let credential = URLCredential(trust: trust)
let pinner = setupCertificatePinner(host: challenge.protectionSpace.host)
if (!pinner.validateCertificateTrustChain(trust)) {
print("failed: invalid certificate chain!")
challenge.sender?.cancel(challenge)
}
if (pinner.validateTrustPublicKeys(trust)) {
completionHandler(.useCredential, credential)
} else {
didPinningFailed = true
print("couldn't validate trust for \(challenge.protectionSpace.host)")
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
迁移到 Alamofire 5 后,没有早期版本中可用的方法sessionDidReceiveChallenge
。
我试过了:
private let session: Session = {
let manager = ServerTrustManager(allHostsMustBeEvaluated: true, evaluators:
["devDomain.com": DisabledTrustEvaluator(),
"prodDomain.com": PublicKeysTrustEvaluator()])
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}()
但是我得到错误:
Error Domain=Alamofire.AFError Code=11 "Server trust evaluation failed due to reason: No public keys were found or provided for evaluation."
更新:
我仍然更喜欢仅使用 256 指纹解析它的方法,因为我们在第一次 api 调用中获得域及其哈希值。
如果您想使用 public 密钥固定,您需要提供用于解析应用程序包中的那些 public 密钥的证书,或者以其他方式将它们提供给 PublicKeysTrustEvaluator
.
首先你需要一个 ServerTrustEvaluating
来处理证书固定,一个简单的工具类似于
public final class CertificatePinnerTrustEvaluator: ServerTrustEvaluating {
public init() {}
func setupCertificatePinner(host: String) -> CertificatePinner {
//get the CertificatePinner
}
public func evaluate(_ trust: SecTrust, forHost host: String) throws {
let pinner = setupCertificatePinner(host: host)
if (!pinner.validateCertificateTrustChain(trust)) {
print("failed: invalid certificate chain!")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
if (!pinner.validateTrustPublicKeys(trust)) {
print ("couldn't validate trust for \(host)")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
}
}
为了能够使用同一个求值器,我建议将 ServerTrustManager
子类化为 return 同一个求值器,我是这样做的:
class CertificatePinnerServerTrustManager: ServerTrustManager {
let evaluator = CertificatePinnerTrustEvaluator()
init() {
super.init(allHostsMustBeEvaluated: true, evaluators: [:])
}
open override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {
return evaluator
}
}
之后您应该准备好创建会话并将管理器传递给它
private let session: Session = {
let trustManager = CertificatePinnerServerTrustManager()
return Session(serverTrustManager: trustManager)
}()
我参考的是第 86 行 SessionDelegate.swift 中 Alamofire 源代码中的方法 urlSession(_:task:didReceive:completionHandler:)
(Alamofire V5.2.1)
我刚换到 Alamofire 5。
之前我使用了 URLSession 和 Certificate Pinner 并且为了处理身份验证挑战我使用了 URLSessionDelegate
的委托方法和散列值
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
print("being challanged! for \(challenge.protectionSpace.host)")
guard let trust = challenge.protectionSpace.serverTrust else {
print("invalid trust!")
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let credential = URLCredential(trust: trust)
let pinner = setupCertificatePinner(host: challenge.protectionSpace.host)
if (!pinner.validateCertificateTrustChain(trust)) {
print("failed: invalid certificate chain!")
challenge.sender?.cancel(challenge)
}
if (pinner.validateTrustPublicKeys(trust)) {
completionHandler(.useCredential, credential)
} else {
didPinningFailed = true
print("couldn't validate trust for \(challenge.protectionSpace.host)")
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
迁移到 Alamofire 5 后,没有早期版本中可用的方法sessionDidReceiveChallenge
。
我试过了:
private let session: Session = {
let manager = ServerTrustManager(allHostsMustBeEvaluated: true, evaluators:
["devDomain.com": DisabledTrustEvaluator(),
"prodDomain.com": PublicKeysTrustEvaluator()])
let configuration = URLSessionConfiguration.af.default
return Session(configuration: configuration, serverTrustManager: manager)
}()
但是我得到错误:
Error Domain=Alamofire.AFError Code=11 "Server trust evaluation failed due to reason: No public keys were found or provided for evaluation."
更新: 我仍然更喜欢仅使用 256 指纹解析它的方法,因为我们在第一次 api 调用中获得域及其哈希值。
如果您想使用 public 密钥固定,您需要提供用于解析应用程序包中的那些 public 密钥的证书,或者以其他方式将它们提供给 PublicKeysTrustEvaluator
.
首先你需要一个 ServerTrustEvaluating
来处理证书固定,一个简单的工具类似于
public final class CertificatePinnerTrustEvaluator: ServerTrustEvaluating {
public init() {}
func setupCertificatePinner(host: String) -> CertificatePinner {
//get the CertificatePinner
}
public func evaluate(_ trust: SecTrust, forHost host: String) throws {
let pinner = setupCertificatePinner(host: host)
if (!pinner.validateCertificateTrustChain(trust)) {
print("failed: invalid certificate chain!")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
if (!pinner.validateTrustPublicKeys(trust)) {
print ("couldn't validate trust for \(host)")
throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
}
}
}
为了能够使用同一个求值器,我建议将 ServerTrustManager
子类化为 return 同一个求值器,我是这样做的:
class CertificatePinnerServerTrustManager: ServerTrustManager {
let evaluator = CertificatePinnerTrustEvaluator()
init() {
super.init(allHostsMustBeEvaluated: true, evaluators: [:])
}
open override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {
return evaluator
}
}
之后您应该准备好创建会话并将管理器传递给它
private let session: Session = {
let trustManager = CertificatePinnerServerTrustManager()
return Session(serverTrustManager: trustManager)
}()
我参考的是第 86 行 SessionDelegate.swift 中 Alamofire 源代码中的方法 urlSession(_:task:didReceive:completionHandler:)
(Alamofire V5.2.1)