如何使用 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 3 或 Swift 4 和 Alamofire 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.com
、site2.foo.com
、....
然后添加 App Transport Security Settings
-> Exception Domains
-> foo.com
字典,包含以下条目。
- NSExceptionRequiresForwardSecrecy : 否
- NSExceptionAllowsInsecureHTTPLoads:是
- NSIncludesSubdomains:是
连接到自签名服务器时出现以下错误。
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 3 或 Swift 4 和 Alamofire 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.com
、site2.foo.com
、....
然后添加 App Transport Security Settings
-> Exception Domains
-> foo.com
字典,包含以下条目。
- NSExceptionRequiresForwardSecrecy : 否
- NSExceptionAllowsInsecureHTTPLoads:是
- NSIncludesSubdomains:是