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)