如何使用 Alamofire 1.3 连接到自签名服务器

How to connect to self signed servers using Alamofire 1.3

连接到自签名服务器时出现以下错误。

Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “maskeddomain.com” which could put your confidential information at risk." UserInfo=0x7fb6dec259e0 {NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=是否仍要连接到服务器?, _kCFStreamErrorCodeKey=-9813, NSUnderlyingError=0x7fb6dbe0dd=90 [=18 ]

Alamofire 1.3 (https://github.com/Alamofire/Alamofire#security) 似乎允许禁用此验证。有没有人实施过这个?我在我的 swift 项目中使用 Alamofire API,不确定 "Server Trust Policy Manager" 需要在哪里实施。请指教

README 中发布了一个示例,演示了在需要时如何禁用求值。

由于您还需要创建自己的 Manager 实例,因此您需要执行以下操作:

class NetworkManager {
    static let sharedInstance = NetworkManager()

    let defaultManager: Alamofire.Manager = {
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "test.example.com": .PinCertificates(
                certificates: ServerTrustPolicy.certificatesInBundle(),
                validateCertificateChain: true,
                validateHost: true
            ),
            "insecure.expired-apis.com": .DisableEvaluation
        ]

        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders

        return Alamofire.Manager(
            configuration: configuration,
            serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )
    }()
}

这将允许您使用 NetworkManager.sharedInstance.defaultManager 对象发出请求。

有一种方法可以更改 Alamofire 管理器共享实例的服务器信任策略,但不推荐这样做。相反,您应该创建自己的自定义管理器实例。这是推荐的解决方案,代码是 Swift 2.0 和来自 swift-2.0 分支 的 Alamofire,在 Xcode7 测试版 5.

正在创建管理器的自定义实例

因为您不会在 Alamofire 上使用 request 方法,而是使用自定义管理器上的方法,所以您需要考虑将管理器存储在何处。我所做的是将它作为静态存储在我的网络包装器中(利用 Alamofire 并处理我的应用程序网络需求的 class)。我是这样设置的:

private static var Manager : Alamofire.Manager = {
        // Create the server trust policies
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "maskeddomain.com": .DisableEvaluation
        ]
        // Create custom manager
        let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
        configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders
        let man = Alamofire.Manager(
            configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
            serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
        )
        return man
    }()

下一步是将所有使用 Alamofire.request() 的调用切换为 Manager.request(),因此您应该有这样的东西:

Manager.request(.GET, "http://whosebug.com").responseJSON(
    completionHandler: { (_, respose, result) -> Void in
            if result.isSuccess {
                // enjoy your success
            } else if result.isFailure {
                // deal with your failure
            }
    })

如果您仍然想更改管理器的共享实例,请转到 here 了解更多信息。

Swift 3Swift 4Alamofire 4[ 的管理器配置:

private static var manager: Alamofire.SessionManager = {

    // Create the server trust policies
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "test.example.com": .disableEvaluation
    ]

    // Create custom manager
    let configuration = URLSessionConfiguration.default
    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
    let manager = Alamofire.SessionManager(
        configuration: URLSessionConfiguration.default,
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )

    return manager
}()

反正@cnoon的回答快满了。但是我遇到了 ssl 验证的另一个麻烦,所以如果有人可以从 it.The manager init 获得帮助,我想把我的代码放在这里:

private var manager: Manager?
// Import the certificates like xxx.cer to your project(anywhere will be fine), then the ServerTrustPolicy.certificatesInBundle() can find them
let serverTrustPolicy = ServerTrustPolicy.PinCertificates(
            certificates: ServerTrustPolicy.certificatesInBundle(),
            validateCertificateChain: false,
            validateHost: true
        )
let serverTrustPolicies: [String : ServerTrustPolicy] = [
            "sub.server.com": .DisableEvaluation, // because the certificates only add the main domain, so disable evaluation for subdomain
            "192.168.0.2:8090": .DisableEvaluation, // the IP address for request data
            "www.server.com": serverTrustPolicy
        ]
manager = Manager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))

然后使用管理员请求:

// this function in the class which for manager the Alamofire request
public func request(method: Alamofire.Method, _ URLString: URLStringConvertible,
                        parameters: [String : AnyObject]?) -> Alamofire.Request
    {
        // we do not need use Alamofire.request now, just use the manager you have initialized
        return manager!.request(method, URLString, parameters: parameters,
                                 headers: ["tokenId": UserManager_Inst.tokenID])
    }

p.s.: 这是swift 2.3 样本

我的项目的另一种方法。 ServerTrustPolicyManager 是一个 open class,它的 serverTrustPolicy 函数也是 open。所以它可以被覆盖。

// For Swift 3 and Alamofire 4.0
open class MyServerTrustPolicyManager: ServerTrustPolicyManager {

    // Override this function in order to trust any self-signed https
    open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
        return ServerTrustPolicy.disableEvaluation

        // or, if `host` contains substring, return `disableEvaluation`
        // Ex: host contains `my_company.com`, then trust it.
    }
}

然后,

    let trustPolicies = MyServerTrustPolicyManager(policies: [:])
    let manager = Alamofire.SessionManager(configuration: sessionConfig, delegate: SessionDelegate(), serverTrustPolicyManager: trustPolicies)

更新@2018,01

为了触发 ServerTrustPolicyManager,需要配置项目的 Info.plist。我找到了解决方案,详细 at this post, cnoon's comment @ 1 Nov 2015.

例如,如果有名为 site1.foo.comsite2.foo.com、.... 然后添加 App Transport Security Settings -> Exception Domains -> foo.com 字典,包含以下条目。

  • NSExceptionRequiresForwardSecrecy : 否
  • NSExceptionAllowsInsecureHTTPLoads:是
  • NSIncludesSubdomains:是

More detail you can refer the post.