使用Alamofire通過HTTPS進行網路請求及證書的使用
本文介紹如何使用 Alamofire 來實現HTTPS網路請求,由於Alamofire就是對URLSession的封裝,所以實現起來區別不大。
- 證書的生成以及伺服器配置
- Alamofire使用HTTPS進行網路請求
- 證書匯入
通過客戶端瀏覽器訪問HTTPS服務需要安裝“mykey.p12”,“tomcat.cer”這兩個證書。同樣,我們開發的應用中也需要把這兩個證書新增進來。同時在 “工程” -> “Build Phases” -> “Copy Bundle Resources” 中新增這兩個證書檔案。 - 配置
Info.plist
由於我們使用的是自簽名的證書,而蘋果ATS(App Transport Security)只信任知名CA頒發的證書,所以在iOS9下即使是HTTPS請求還是會被ATS攔截。
所以在Info.plist下新增如下配置(iOS8不需要):
- 證書匯入
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
- 使用兩個證書進行雙向驗證以及網路請求
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
}
- 只使用一個客戶端證書
由於我們使用的是自簽名的證書,那麼對伺服器的認證全由客戶端這邊判斷。也就是說其實使用一個客戶端證書“mykey.p12”也是可以的(專案中也只需匯入一個證書)。
當對伺服器進行驗證的時候,判斷服務主機地址是否正確,是的話信任即可
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的使用Swift
- 使用retrofit進行網路請求
- Android開發 - Retrofit 2 使用自簽名的HTTPS證書進行API請求AndroidHTTPAPI
- 關於httpclient 請求https (如何繞過證書驗證)HTTPclient
- 使用 http-proxy 對網路請求進行代理HTTP
- 使用Moya庫,進行https證書校驗HTTP
- Moya,KingFisher中使用自簽名證書發起HTTPS請求HTTP
- 使用acme申請https免費證書ACMHTTP
- 使用 Acme.sh 申請 https 證書ACMHTTP
- React Native 探索(五)使用 fetch 進行網路請求React Native
- React Native探索(五)使用fetch進行網路請求React Native
- 使用 gorilla/mux 進行 HTTP 請求路由和驗證GoUXHTTP路由
- Jmeter進行HTTPS介面壓測及SSL證書驗證JMeterHTTP
- iOS 使用Moya網路請求iOS
- 使用 $fetch 進行 HTTP 請求HTTP
- 通過配置http攔截器,來進行ajax請求驗證使用者登入的頁面跳轉HTTP
- Swift 中的網路請求問題 OC(AFNetworking) && Swift(Alamofire)Swift
- 阿里雲免費Https證書申請使用阿里HTTP
- 通過Socket進行Http/Https 網頁操作HTTP網頁
- Android 使用ksoap進行webservice請求AndroidWeb
- 建立並使用https證書HTTP
- okhttp網路請求框架的簡單使用HTTP框架
- 騰訊雲:免費SSL證書實現https請求HTTP
- 輕鬆搞定Retrofit不同網路請求方式的請求引數配置,及常用註解使用
- 通過 Apache Commons HttpClient 傳送 HTTPS 請求ApacheHTTPclient
- 網路通訊5:執行HTTP的GET/POST請求HTTP
- 證書-雙證書請求檔案
- C#使用命名管道通過網路在程式之間進行通訊C#
- flutter網路請求框架dio基本使用Flutter框架
- 使用fidder進行post和get請求
- 使用 Laravel 請求類來驗證表單請求Laravel
- 使用https證書的好處都有哪些?HTTP
- 初探計算機網路之HTTPS請求計算機網路HTTP
- 通過進攻心態進行有效的網路防禦
- vue(24)網路請求模組axios使用VueiOS
- 如何使用 Python 請求網路資源Python
- 使用Retrofit+RxJava實現網路請求RxJava
- [譯]使用 Siesta 處理 Swift 網路請求Swift