(本文代码已升级至Swift3)
我原来写过一篇文章介绍如何使用证书通过SSL/TLS方式进行网络请求( Swift - 使用URLSession通过HTTPS进行网络请求,及证书的使用),当时用的是 URLSession。
本文介绍如何使用 Alamofire 来实现HTTPS网络请求,由于Alamofire就是对URLSession的封装,所以实现起来区别不大。
(如果Alamofire的配置使用不了解的,可以先去看看我原来写的文章: Swift - HTTP网络操作库Alamofire使用详解)
3,使用两个证书进行双向验证,以及网络请求
控制台打印输出如下:
4,只使用一个客户端证书
由于我们使用的是自签名的证书,那么对服务器的认证全由客户端这边判断。也就是说其实使用一个客户端证书“ mykey.p12”也是可以的(项目中也只需导入一个证书)。
当对服务器进行验证的时候,判断服务主机地址是否正确,是的话信任即可(代码高亮部分)
原文出自: www.hangge.com 转载请保留原文链接: http://www.hangge.com/blog/cache/detail_1052.html
我原来写过一篇文章介绍如何使用证书通过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
)
}
}
//数据请求
.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
)
}
}
//数据请求
.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