Alamofire自簽名證書配置使用

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

一供置,證書的生成谨湘,以及服務(wù)器配置

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

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

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

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

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

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

3边琉,使用兩個(gè)證書進(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ù)器證書

            
if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodServerTrust
 {

                
print
(
"服務(wù)端證書認(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)證客戶端證書

            
else
 if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodClientCertificate
 {

                
print
(
"客戶端證書認(rèn)證变姨!"
)

                
//獲取客戶端證書相關(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)

        
}

    
}

    
 
    
//獲取客戶端證書相關(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"
] 
//客戶端證書密碼

        
//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è)客戶端證書由于我們使用的是自簽名的證書,那么對(duì)服務(wù)器的認(rèn)證全由客戶端這邊判斷蹄衷。也就是說其實(shí)使用一個(gè)客戶端證書“mykey.p12”也是可以的(項(xiàng)目中也只需導(dǎo)入一個(gè)證書)忧额。當(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ù)器證書認(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)證客戶端證書

            
else
 if
 challenge.protectionSpace.authenticationMethod

                
== 
NSURLAuthenticationMethodClientCertificate
 {

                
print
(
"客戶端證書認(rèn)證耍属!"
)

                
//獲取客戶端證書相關(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)

        
}

    
}

    
 
    
//獲取客戶端證書相關(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"
] 
//客戶端證書密碼

        
//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通過HTTPS進(jìn)行網(wǎng)絡(luò)請(qǐng)求巩检,及證書的使用
本人記錄下來以防后續(xù)需要用到

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厚骗,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兢哭,更是在濱河造成了極大的恐慌领舰,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迟螺,死亡現(xiàn)場(chǎng)離奇詭異冲秽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矩父,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門锉桑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人窍株,你說我怎么就攤上這事民轴」ツ” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵后裸,是天一觀的道長(zhǎng)瑰钮。 經(jīng)常有香客問我,道長(zhǎng)微驶,這世上最難降的妖魔是什么飞涂? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮祈搜,結(jié)果婚禮上较店,老公的妹妹穿的比我還像新娘。我一直安慰自己容燕,他們只是感情好梁呈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蘸秘,像睡著了一般官卡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上醋虏,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天寻咒,我揣著相機(jī)與錄音,去河邊找鬼颈嚼。 笑死毛秘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阻课。 我是一名探鬼主播叫挟,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼限煞!你這毒婦竟也來了抹恳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤署驻,失蹤者是張志新(化名)和其女友劉穎奋献,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旺上,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓶蚂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了抚官。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扬跋。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凌节,靈堂內(nèi)的尸體忽然破棺而出钦听,到底是詐尸還是另有隱情洒试,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布朴上,位于F島的核電站垒棋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痪宰。R本人自食惡果不足惜叼架,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望衣撬。 院中可真熱鬧乖订,春花似錦、人聲如沸具练。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)扛点。三九已至哥遮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陵究,已是汗流浹背眠饮。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铜邮,地道東北人仪召。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像牲距,于是被迫代替她去往敵國(guó)和親返咱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容