-
swift和oc一样,都是苹果的app研发语言,苹果推荐大家都使用https,所以难以避免的遇到ssl证书使用自签名证书的情况(测试服务器等情况)
-
而自签名证书,在苹果看来,也是不安全的。所以默认情况下,是不能正常访问的。
-
刚好做了一个App,使用swift访问https自签名服务器,记录一下处理方法。
A、Alamofire框架体系下,处理自签名URL的方法
// 生成对应Url的Session,如果这个URL对应的host已经被注册,返回已有的Session即可。
fileprivate static func generalSession(url: String, redirect: Redirector = Redirector.follow) -> Session {
// 查看是否包含url对应的host
var theHost: String = "";
do {
let regex = try NSRegularExpression(pattern: ".*?://(.*?)/.*", options: .caseInsensitive)
theHost = regex.stringByReplacingMatches(in: url, options: .anchored, range: NSMakeRange(0, url.count), withTemplate: "$1")
} catch {
}
if (!lztHostEvaluators.keys.contains(theHost)) {
lztHostEvaluators[theHost] = DisabledTrustEvaluator();
let host = URL.init(string: url)?.host ?? ""
lztHostEvaluators[host] = DisabledTrustEvaluator();
// lztHostEvaluators[host] = PinnedCertificatesTrustEvaluator(acceptSelfSignedCertificates: true);
}
// 服务器访问证书的验证模式
let manager = ServerTrustManager(evaluators: lztHostEvaluators)
let logger = LztNetworkLogger()
// 创建Session
lztUrlSession = Session(serverTrustManager: manager, redirectHandler: redirect, eventMonitors: [logger])
return lztUrlSession
// return Session.default;
}
这样,使用session.request就可以访问自签名证书的URL了。
B、 使用swift自带的URLSession的方式,访问自签名URL
extension ImageLoader: URLSessionDelegate {
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// 使用自签名证书认证
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
// 打印错误日志
if let err = error {
print("Error: \(err.localizedDescription)")
} else {
print("Error. Giving up")
}
}
}
extension ImageLoader: URLSessionDataDelegate {
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didBecome streamTask: URLSessionStreamTask) {
streamTask.resume()
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didBecome downloadTask: URLSessionDownloadTask) {
downloadTask.resume()
}
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// 这里也一样,接收自签名证书
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
// 错误日志打印
if let err = error {
print("Error: \(err.localizedDescription)")
} else {
print("Error. Giving up")
}
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: (URLSession.ResponseDisposition) -> Void) {
// 接收请求
completionHandler(URLSession.ResponseDisposition.allow)
}
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
session.finishTasksAndInvalidate()
}
}
/// 定义Session,后续使用 session.dataTask(with: rUrl) {// do some thing } 就好了。
private lazy var session: URLSession = {
let config = URLSessionConfiguration.default
config.urlCache = cache
config.requestCachePolicy = .returnCacheDataElseLoad
return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
}()
-
注意第一种方式,我尝试使用 PinnedCertificatesTrustEvaluator(acceptSelfSignedCertificates: true) 这个方法,不好使。看起来这应该是好使的,也许是我哪里写错了也不一定。
-
除了以上的代码以外,还需要做一些配置,在info.plist文件中添加代码(也可以操作界面)
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
-
以上方案可以解决类似:AppName[44835:3182593] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
这样的问题。 -
感谢:https://gist.github.com/stinger/420107a71a02995c312036eb7919e9f9
-
感谢各位的阅读,如果有错误或者有什么问题,请大家留言。我的代码一般都是拿来即用的,基本不需要修改。
-
环境:swift5.7 , AppCode 2022.3.2,XCode Version 14.2 (14C18)
评论区