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

(本文代码已升级至Swift3) 

我原来写过一篇文章介绍如何使用证书通过SSL/TLS方式进行网络请求( Swift - 使用URLSession通过HTTPS进行网络请求,及证书的使用),当时用的是 URLSession
本文介绍如何使用 Alamofire 来实现HTTPS网络请求,由于Alamofire就是对URLSession的封装,所以实现起来区别不大。
(如果Alamofire的配置使用不了解的,可以先去看看我原来写的文章: Swift - HTTP网络操作库Alamofire使用详解

一,证书的生成,以及服务器配置
文章详细介绍了HTTPS,SSL/TLS。还有使用key tool生成自签名证书,Tomcat下https服务的配置。

二,Alamofire使用HTTPS进行网络请求
1,证书导入
前面文章介绍了通过客户端浏览器访问HTTPS服务需,需要安装“ mykey.p12”,“ tomcat.cer”这两个证书。同样,我们开发的应用中也需要把这两个证书添加进来。
原文:Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用

记的同时在 “ 工程” -> “ Build Phases” -> “ Copy Bundle Resources” 中添加这两个证书文件。
原文:Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用


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
}
控制台打印输出如下:
原文:Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值