Alamofire自簽名證書(shū)配置使用

我原來(lái)寫(xiě)過(guò)一篇文章介紹如何使用證書(shū)通過(guò)SSL/TLS方式進(jìn)行網(wǎng)絡(luò)請(qǐng)求(Swift - 使用URLSession通過(guò)HTTPS進(jìn)行網(wǎng)絡(luò)請(qǐng)求,及證書(shū)的使用),當(dāng)時(shí)用的是 URLSession。本文介紹如何使用 Alamofire 來(lái)實(shí)現(xiàn)HTTPS網(wǎng)絡(luò)請(qǐng)求,由于Alamofire就是對(duì)URLSession的封裝,所以實(shí)現(xiàn)起來(lái)區(qū)別不大。(如果Alamofire的配置使用不了解的,可以先去看看我原來(lái)寫(xiě)的文章:Swift - HTTP網(wǎng)絡(luò)操作庫(kù)Alamofire使用詳解

一,證書(shū)的生成,以及服務(wù)器配置

參考我前面寫(xiě)的這篇文章:Tomcat服務(wù)器配置https雙向認(rèn)證(使用keytool生成證書(shū))
文章詳細(xì)介紹了HTTPS,SSL/TLS。還有使用key tool生成自簽名證書(shū),Tomcat下https服務(wù)的配置。

二,Alamofire使用HTTPS進(jìn)行網(wǎng)絡(luò)請(qǐng)求

1,證書(shū)導(dǎo)入
前面文章介紹了通過(guò)客戶端瀏覽器訪問(wèn)HTTPS服務(wù)需,需要安裝“mykey.p12”,“tomcat.cer”這兩個(gè)證書(shū)。同樣,我們開(kāi)發(fā)的應(yīng)用中也需要把這兩個(gè)證書(shū)添加進(jìn)來(lái)。

記的同時(shí)在 “工程” -> “Build Phases” -> “Copy Bundle Resources” 中添加這兩個(gè)證書(shū)文件。

2,配置Info.plist
由于我們使用的是自簽名的證書(shū),而蘋(píng)果ATS(App Transport Security)只信任知名CA頒發(fā)的證書(shū),所以在iOS9下即使是HTTPS請(qǐng)求還是會(huì)被ATS攔截。
所以在Info.plist下添加如下配置(iOS8不需要):

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>

3,使用兩個(gè)證書(shū)進(jìn)行雙向驗(yàn)證,以及網(wǎng)絡(luò)請(qǐng)求

import
 UIKit

import
 Alamofire

 
class
 ViewController
: 
UIViewController
 {

    
 
    
override
 func
 viewDidLoad() {

        
super
.viewDidLoad()

        
 
        
//認(rèn)證相關(guān)設(shè)置

        
let
 manager = 
SessionManager
.
default

        
manager.delegate.sessionDidReceiveChallenge = { session, challenge 
in

            
//認(rèn)證服務(wù)器證書(shū)

            
if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodServerTrust
 {

                
print
(
"服務(wù)端證書(shū)認(rèn)證!"
)

                
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
)

                
}

            
}

            
//認(rèn)證客戶端證書(shū)

            
else
 if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodClientCertificate
 {

                
print
(
"客戶端證書(shū)認(rèn)證!"
)

                
//獲取客戶端證書(shū)相關(guān)信息

                
let
 identityAndTrust:
IdentityAndTrust
 = 
self
.extractIdentity();

                
 
                
let
 urlCredential:
URLCredential
 = 
URLCredential
(

                    
identity: identityAndTrust.identityRef,

                    
certificates: identityAndTrust.certArray 
as
? [
AnyObject
],

                    
persistence: 
URLCredential
.
Persistence
.forSession);

                
 
                
return
 (.useCredential, urlCredential);

            
}

            
// 其它情況(不接受認(rèn)證)

            
else
 {

                
print
(
"其它情況(不接受認(rèn)證)"
)

                
return
 (.cancelAuthenticationChallenge, 
nil
)

            
}

        
}

        
 
        
//數(shù)據(jù)請(qǐng)求

        
Alamofire
.request(
"[https://192.168.1.112:8443](https://192.168.1.112:8443/)"
)

            
.responseString { response 
in

                
print
(response)

        
}

    
}

    
 
    
//獲取客戶端證書(shū)相關(guān)信息

    
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"
] 
//客戶端證書(shū)密碼

        
//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()

    
}

}

 
//定義一個(gè)結(jié)構(gòu)體,存儲(chǔ)認(rèn)證相關(guān)信息

struct
 IdentityAndTrust
 {

    
var
 identityRef:
SecIdentity

    
var
 trust:
SecTrust

    
var
 certArray:
AnyObject

}

控制臺(tái)打印輸出如下:

4,只使用一個(gè)客戶端證書(shū)由于我們使用的是自簽名的證書(shū),那么對(duì)服務(wù)器的認(rèn)證全由客戶端這邊判斷。也就是說(shuō)其實(shí)使用一個(gè)客戶端證書(shū)“mykey.p12”也是可以的(項(xiàng)目中也只需導(dǎo)入一個(gè)證書(shū))。當(dāng)對(duì)服務(wù)器進(jìn)行驗(yàn)證的時(shí)候,判斷服務(wù)主機(jī)地址是否正確,是的話信任即可(代碼高亮部分)

import
 UIKit

import
 Alamofire

 
class
 ViewController
: 
UIViewController
 {

    
 
    
//自簽名網(wǎng)站地址

    
let
 selfSignedHosts = [
"192.168.1.112"
, 
"www.hangge.com"
]

    
 
    
override
 func
 viewDidLoad() {

        
super
.viewDidLoad()

        
 
        
//認(rèn)證相關(guān)設(shè)置

        
let
 manager = 
SessionManager
.
default

        
manager.delegate.sessionDidReceiveChallenge = { session, challenge 
in

            
//認(rèn)證服務(wù)器(這里不使用服務(wù)器證書(shū)認(rèn)證,只需地址是我們定義的幾個(gè)地址即可信任)

            
if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodServerTrust

                
&& 
self
.selfSignedHosts.contains(challenge.protectionSpace.host) {

                
print
(
"服務(wù)器認(rèn)證!"
)

                
let
 credential = 
URLCredential
(trust: challenge.protectionSpace.serverTrust!)

                
return
 (.useCredential, credential)

            
}

            
//認(rèn)證客戶端證書(shū)

            
else
 if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodClientCertificate
 {

                
print
(
"客戶端證書(shū)認(rèn)證!"
)

                
//獲取客戶端證書(shū)相關(guān)信息

                
let
 identityAndTrust:
IdentityAndTrust
 = 
self
.extractIdentity();

                
 
                
let
 urlCredential:
URLCredential
 = 
URLCredential
(

                    
identity: identityAndTrust.identityRef,

                    
certificates: identityAndTrust.certArray 
as
? [
AnyObject
],

                    
persistence: 
URLCredential
.
Persistence
.forSession);

                
 
                
return
 (.useCredential, urlCredential);

            
}

            
// 其它情況(不接受認(rèn)證)

            
else
 {

                
print
(
"其它情況(不接受認(rèn)證)"
)

                
return
 (.cancelAuthenticationChallenge, 
nil
)

            
}

        
}

        
 
        
//數(shù)據(jù)請(qǐng)求

        
Alamofire
.request(
"[https://192.168.1.112:8443](https://192.168.1.112:8443/)"
)

            
.responseString { response 
in

                
print
(response)

        
}

    
}

    
 
    
//獲取客戶端證書(shū)相關(guān)信息

    
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"
] 
//客戶端證書(shū)密碼

        
//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()

    
}

}

 
//定義一個(gè)結(jié)構(gòu)體,存儲(chǔ)認(rèn)證相關(guān)信息

struct IdentityAndTrust
 {
var identityRef: SecIdentity    
var trust: SecTrust
var certArray: AnyObject

}

聲明

本文轉(zhuǎn)自Swift - 使用Alamofire通過(guò)HTTPS進(jìn)行網(wǎng)絡(luò)請(qǐng)求,及證書(shū)的使用
本人記錄下來(lái)以防后續(xù)需要用到

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容