(本文代码已升级至Swift3)


我原来写过一篇文章介绍如何使用证书通过SSL/TLS方式进行网络请求(Swift - 使用URLSession通过HTTPS进行网络请求,及证书的使用),当时用的是 URLSession
本文介绍如何使用 Alamofire 来实现HTTPS网络请求,由于Alamofire就是对URLSession的封装,所以实现起来区别不大。
(如果Alamofire的配置使用不了解的,可以先去看看我原来写的文章:Swift - HTTP网络操作库Alamofire使用详解)
一,证书的生成,以及服务器配置
参考我前面写的这篇文章:Tomcat服务器配置https双向认证(使用keytool生成证书)
文章详细介绍了HTTPS,SSL/TLS。还有使用key tool生成自签名证书,Tomcat下https服务的配置。
二,Alamofire使用HTTPS进行网络请求
1,证书导入
前面文章介绍了通过客户端浏览器访问HTTPS服务需,需要安装“mykey.p12”,“tomcat.cer”这两个证书。同样,我们开发的应用中也需要把这两个证书添加进来。
记的同时在 “工程” -> “Build Phases” -> “Copy Bundle Resources” 中添加这两个证书文件。
2,配置Info.plist
由于我们使用的是自签名的证书,而苹果ATS(App Transport Security)只信任知名CA颁发的证书,所以在iOS9下即使是HTTPS请求还是会被ATS拦截。
所以在Info.plist下添加如下配置(iOS8不需要):
1
2
3
4
5
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

3,使用两个证书进行双向验证,以及网络请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import UIKit
import Alamofire
class ViewController: UIViewController {
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //认证相关设置
        let manager = SessionManager.default
        manager.delegate.sessionDidReceiveChallenge = { session, challenge in
            //认证服务器证书
            if challenge.protectionSpace.authenticationMethod
                == NSURLAuthenticationMethodServerTrust {
                print("服务端证书认证!")
                let serverTrust:SecTrust = challenge.protectionSpace.serverTrust!
                let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0)!
                let remoteCertificateData
                    = CFBridgingRetain(SecCertificateCopyData(certificate))!
                let cerPath = Bundle.main.path(forResource: "tomcat", ofType: "cer")!
                let cerUrl = URL(fileURLWithPath:cerPath)
                let localCertificateData = try! Data(contentsOf: cerUrl)
                 
                if (remoteCertificateData.isEqual(localCertificateData) == true) {
                     
                    let credential = URLCredential(trust: serverTrust)
                    challenge.sender?.use(credential, for: challenge)
                    return (URLSession.AuthChallengeDisposition.useCredential,
                            URLCredential(trust: challenge.protectionSpace.serverTrust!))
                     
                } else {
                    return (.cancelAuthenticationChallenge, nil)
                }
            }
            //认证客户端证书
            else if challenge.protectionSpace.authenticationMethod
                == NSURLAuthenticationMethodClientCertificate {
                print("客户端证书认证!")
                //获取客户端证书相关信息
                let identityAndTrust:IdentityAndTrust = self.extractIdentity();
                 
                let urlCredential:URLCredential = URLCredential(
                    identity: identityAndTrust.identityRef,
                    certificates: identityAndTrust.certArray as? [AnyObject],
                    persistence: URLCredential.Persistence.forSession);
                 
                return (.useCredential, urlCredential);
            }
            // 其它情况(不接受认证)
            else {
                print("其它情况(不接受认证)")
                return (.cancelAuthenticationChallenge, nil)
            }
        }
         
        //数据请求
        Alamofire.request("https://192.168.1.112:8443")
            .responseString { response in
                print(response)
        }
    }
     
    //获取客户端证书相关信息
    func extractIdentity() -> IdentityAndTrust {
        var identityAndTrust:IdentityAndTrust!
        var securityError:OSStatus = errSecSuccess
         
        let path: String = Bundle.main.path(forResource: "mykey", ofType: "p12")!
        let PKCS12Data = NSData(contentsOfFile:path)!
        let key : NSString = kSecImportExportPassphrase as NSString
        let options : NSDictionary = [key : "123456"] //客户端证书密码
        //create variable for holding security information
        //var privateKeyRef: SecKeyRef? = nil
         
        var items : CFArray?
         
        securityError = SecPKCS12Import(PKCS12Data, options, &items)
         
        if securityError == errSecSuccess {
            let certItems:CFArray = items as CFArray!;
            let certItemsArray:Array = certItems as Array
            let dict:AnyObject? = certItemsArray.first;
            if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {
                // grab the identity
                let identityPointer:AnyObject? = certEntry["identity"];
                let secIdentityRef:SecIdentity = identityPointer as! SecIdentity!
                print("\(identityPointer)  :::: \(secIdentityRef)")
                // grab the trust
                let trustPointer:AnyObject? = certEntry["trust"]
                let trustRef:SecTrust = trustPointer as! SecTrust
                print("\(trustPointer)  :::: \(trustRef)")
                // grab the cert
                let chainPointer:AnyObject? = certEntry["chain"]
                identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef,
                                        trust: trustRef, certArray:  chainPointer!)
            }
        }
        return identityAndTrust;
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
//定义一个结构体,存储认证相关信息
struct IdentityAndTrust {
    var identityRef:SecIdentity
    var trust:SecTrust
    var certArray:AnyObject
}

控制台打印输出如下:

4,只使用一个客户端证书
由于我们使用的是自签名的证书,那么对服务器的认证全由客户端这边判断。也就是说其实使用一个客户端证书“mykey.p12”也是可以的(项目中也只需导入一个证书)。
当对服务器进行验证的时候,判断服务主机地址是否正确,是的话信任即可(代码高亮部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import UIKit
import Alamofire
class ViewController: UIViewController {
     
    //自签名网站地址
    let selfSignedHosts = ["192.168.1.112", "www.hangge.com"]
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //认证相关设置
        let manager = SessionManager.default
        manager.delegate.sessionDidReceiveChallenge = { session, challenge in
            //认证服务器(这里不使用服务器证书认证,只需地址是我们定义的几个地址即可信任)
            if challenge.protectionSpace.authenticationMethod
                == NSURLAuthenticationMethodServerTrust
                && self.selfSignedHosts.contains(challenge.protectionSpace.host) {
                print("服务器认证!")
                let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
                return (.useCredential, credential)
            }
            //认证客户端证书
            else if challenge.protectionSpace.authenticationMethod
                == NSURLAuthenticationMethodClientCertificate {
                print("客户端证书认证!")
                //获取客户端证书相关信息
                let identityAndTrust:IdentityAndTrust = self.extractIdentity();
                 
                let urlCredential:URLCredential = URLCredential(
                    identity: identityAndTrust.identityRef,
                    certificates: identityAndTrust.certArray as? [AnyObject],
                    persistence: URLCredential.Persistence.forSession);
                 
                return (.useCredential, urlCredential);
            }
            // 其它情况(不接受认证)
            else {
                print("其它情况(不接受认证)")
                return (.cancelAuthenticationChallenge, nil)
            }
        }
         
        //数据请求
        Alamofire.request("https://192.168.1.112:8443")
            .responseString { response in
                print(response)
        }
    }
     
    //获取客户端证书相关信息
    func extractIdentity() -> IdentityAndTrust {
        var identityAndTrust:IdentityAndTrust!
        var securityError:OSStatus = errSecSuccess
         
        let path: String = Bundle.main.path(forResource: "mykey", ofType: "p12")!
        let PKCS12Data = NSData(contentsOfFile:path)!
        let key : NSString = kSecImportExportPassphrase as NSString
        let options : NSDictionary = [key : "123456"] //客户端证书密码
        //create variable for holding security information
        //var privateKeyRef: SecKeyRef? = nil
         
        var items : CFArray?
         
        securityError = SecPKCS12Import(PKCS12Data, options, &items)
         
        if securityError == errSecSuccess {
            let certItems:CFArray = items as CFArray!;
            let certItemsArray:Array = certItems as Array
            let dict:AnyObject? = certItemsArray.first;
            if let certEntry:Dictionary = dict as? Dictionary<String, AnyObject> {
                // grab the identity
                let identityPointer:AnyObject? = certEntry["identity"];
                let secIdentityRef:SecIdentity = identityPointer as! SecIdentity!
                print("\(identityPointer)  :::: \(secIdentityRef)")
                // grab the trust
                let trustPointer:AnyObject? = certEntry["trust"]
                let trustRef:SecTrust = trustPointer as! SecTrust
                print("\(trustPointer)  :::: \(trustRef)")
                // grab the cert
                let chainPointer:AnyObject? = certEntry["chain"]
                identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef,
                                        trust: trustRef, certArray:  chainPointer!)
            }
        }
        return identityAndTrust;
    }
     
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
//定义一个结构体,存储认证相关信息
struct IdentityAndTrust {
    var identityRef:SecIdentity
    var trust:SecTrust
    var certArray:AnyObject
}

原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1052.html

Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用相关推荐

  1. Swift - 使用SwiftHTTP通过HTTPS进行网络请求,及证书的使用

    (本文代码已升级至Swift3) 一,证书的生成,以及服务器配置 参考我前面写的这篇文章:Tomcat服务器配置https双向认证(使用keytool生成证书) 文章详细介绍了HTTPS,SSL/TL ...

  2. 深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求(上)

    2019独角兽企业重金招聘Python工程师标准>>> 深入理解HTTPS及在iOS系统中适配HTTPS类型网络请求 一.引言 本篇博客主要讨论如何在客户端与服务端之间进行HTTPS ...

  3. Https的数据请求的证书设置

    对于https的网络请求很多人都比较头疼,不止iOS包括pc端和移动端的很多请求都离不开https CFNetwork SSLHandshake failed (-9806) error = Erro ...

  4. HTTP HTTPS 及网络请求与响应

    HTTP URI的全称为 Uniform Resource Identifier,即统一资源标志符 URL的全称为 Universal Resource Locator,即统一资源定位符 URL是UR ...

  5. 使用WeexSDK,网络请求信任证书的问题

    使用0.18.0版本的weexSDK,并且是手动导入的SDK. 在项目中创建一个SDResourceRequest(名字随意)类继承WXResourceRequestHandlerDefaultImp ...

  6. Swift基础之使用Alamofire库进行网络请求和断点下载

    好久没有写过Swift相关的文章博客了,这里我就展示一下关于使用Alamofire库的方法 1.什么是Alamofire (1)Alamofire 的前身是 AFNetworking.AFNetwor ...

  7. Swift 网络请求库Moya的使用

    Moya是Swift中的网络库Alamofire的二次封装,Alamofire本身使用起来是很简单方便的,例子如下: func loadData(){var param = [String:Strin ...

  8. 通过 Moya + RxSwift + Argo 完成网络请求

    作者:@请叫我汪二 授权本站转载. 最近在新项目中尝试使用 Moya+RxSwift+Argo 进行网络请求和解析,感觉还阔以,再来给大家安利一波. Moya Moya 是一个基于 Alamofire ...

  9. iOS 网络请求劫持

    1.概述: NSURLProtocol是URL loading system 中的一个重要的组成部分,它允许我们对全局的网络请求(基于使用URLRequest)做拦截,可拦截的请求类型有NSURLCo ...

最新文章

  1. Cookie和Session的区别与联系
  2. linux sed命令 常用方法
  3. C#连接sqlserver数据库
  4. ArcGIS Server 部署与配置
  5. python网页请求_python用post请求网页
  6. 【PDF下载】无意中发现的另三本统计学入门好书
  7. 转帖不会乱码的,powershell网络蜘蛛
  8. 消息队列重要机制讲解以及MQ设计思路(kafka、rabbitmq、rocketmq)
  9. 何兆武:西南联大的数学家
  10. php获取继承类方法吗,php如何获取当前类名,继承中的问题?
  11. 开关电源怎么测试文波_开关电源环路增益测试
  12. 淘宝潜规折射出的人性
  13. 网页内容复制粘贴(三种方案 兼容多种浏览器)
  14. 线下商店销量预测挑战赛
  15. UGUI实现图片特效轮播,使用插件DOTWEEN
  16. 总结:K8S之pod配置
  17. 高通qspr是哪几个单词得缩写_无线通讯中的TX/RX具体所指什么? 是哪几个单词的缩写?...
  18. uiautomator2+ tesseract 智能识别文字实现手游辅助外挂,打怪刷装备快人一步
  19. JS之解构( Destructuring)
  20. php activemq实例,php操作ActiveMQ - 小周博客,小周个人博客,程序猿小王子,技术博客,个人博客模板,php博客系统,设计模式,wzyl - 黑夜遮不住光亮...

热门文章

  1. 已知空间一点到另外两点直线的距离
  2. 如何发布ActiveX 控件
  3. 图像空间变换--imtransform
  4. linux php进程端口占用,linux如何查看端口占用情况
  5. html中设置表格单实线,css实现表格实线的方法
  6. php上传图片 $__files没有信息_Python接口测试文件上传实例解析
  7. 批量关闭公众号推送_微信推出“一键拒收”长期未读公众号推送功能
  8. mysql udf 性能_适当的mysql udf
  9. 【蓝桥java】递归基础之39级台阶
  10. 网上商城系统源代码_多用户系统商城授权有几种方式?