2,配置Info.plist
由于我们使用的是自签名的证书,而苹果ATS(App Transport Security)只信任知名CA颁发的证书,所以在iOS9下即使是HTTPS请求还是会被ATS拦截。
所以在Info.plist下添加如下配置(iOS8不需要):
3,使用两个证书进行双向验证,以及网络请求
import UIKit
import Foundation
class ViewController: UIViewController, NSURLSessionDelegate {
override func viewDidLoad() {
super.viewDidLoad()
//获取数据
httpGet(NSMutableURLRequest(URL: NSURL(string: "https://192.168.1.101:8443")!))
}
// 使用NSURLSession请求数据
func httpGet(request: NSMutableURLRequest!) {
let configuration =
NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration,
delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let dataTask = session.dataTaskWithRequest(request,
completionHandler: {(data, response, error) -> Void in
if error != nil{
print(error?.code)
print(error?.description)
}else{
let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("访问成功,获取数据如下:")
print(str)
}
}) as NSURLSessionTask
//使用resume方法启动任务
dataTask.resume()
}
// 在访问资源的时候,如果服务器返回需要授权(提供一个NSURLCredential对象)
// 那么该方法就回被调用(这个是NSURLSessionDelegate代理方法)
func URLSession(session: NSURLSession,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?)
-> Void) {
//认证服务器证书
if challenge.protectionSpace.authenticationMethod
== (NSURLAuthenticationMethodServerTrust) {
print("服务端证书认证!")
let serverTrust:SecTrustRef = challenge.protectionSpace.serverTrust!
let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0)!
let remoteCertificateData
= CFBridgingRetain(SecCertificateCopyData(certificate))!
let cerPath = NSBundle.mainBundle().pathForResource("tomcat",
ofType: "cer")!
let localCertificateData = NSData(contentsOfFile:cerPath)!
if (remoteCertificateData.isEqualToData(localCertificateData) == true) {
let credential = NSURLCredential(forTrust: serverTrust)
challenge.sender?.useCredential(credential,
forAuthenticationChallenge: challenge)
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential,
NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
} else {
completionHandler(.CancelAuthenticationChallenge, nil)
}
}
//认证客户端证书
else if challenge.protectionSpace.authenticationMethod
== NSURLAuthenticationMethodClientCertificate
{
print("客户端证书认证!")
//获取客户端证书相关信息
let identityAndTrust:IdentityAndTrust = self.extractIdentity();
let urlCredential:NSURLCredential = NSURLCredential(
identity: identityAndTrust.identityRef,
certificates: identityAndTrust.certArray as? [AnyObject],
persistence: NSURLCredentialPersistence.ForSession);
completionHandler(.UseCredential, urlCredential);
}
// 其它情况(不接受认证)
else {
print("其它情况(不接受认证)")
completionHandler(.CancelAuthenticationChallenge, nil);
}
}
//获取客户端证书相关信息
func extractIdentity() -> IdentityAndTrust {
var identityAndTrust:IdentityAndTrust!
var securityError:OSStatus = errSecSuccess
let path: String = NSBundle.mainBundle().pathForResource("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
// grab the identity
let identityPointer:AnyObject? = certEntry["identity"];
let secIdentityRef:SecIdentityRef = identityPointer as! SecIdentityRef!;
print("(identityPointer) :::: (secIdentityRef)")
// grab the trust
let trustPointer:AnyObject? = certEntry["trust"];
let trustRef:SecTrustRef = trustPointer as! SecTrustRef;
print("(trustPointer) :::: (trustRef)")
// grab the cert
let chainPointer:AnyObject? = certEntry["chain"];
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef,
trust: trustRef, certArray: chainPointer!);
}
}
return identityAndTrust;
}
}
//定义一个结构体,存储认证相关信息
struct IdentityAndTrust {
var identityRef:SecIdentityRef
var trust:SecTrustRef
var certArray:AnyObject
}
控制台打印输出如下:
4,只使用一个客户端证书
由于我们使用的是自签名的证书,那么对服务器的认证全由客户端这边判断。也就是说其实使用一个客户端证书“mykey.p12”也是可以的(项目中也只需导入一个证书)。
当对服务器进行验证的时候,判断服务主机地址是否正确,是的话信任即可(代码高亮部分)
import UIKit
import Foundation
class ViewController: UIViewController, NSURLSessionDelegate {
//自签名网站地址
let selfSignedHosts = ["192.168.1.101", "www.hangge.com"]
override func viewDidLoad() {
super.viewDidLoad()
//获取数据
httpGet(NSMutableURLRequest(URL: NSURL(string: "https://192.168.1.101:8443")!))
}
// 使用NSURLSession请求数据
func httpGet(request: NSMutableURLRequest!) {
let configuration =
NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration,
delegate: self, delegateQueue:NSOperationQueue.mainQueue())
let dataTask = session.dataTaskWithRequest(request,
completionHandler: {(data, response, error) -> Void in
if error != nil{
print(error?.code)
print(error?.description)
}else{
let str = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("访问成功,获取数据如下:")
print(str)
}
}) as NSURLSessionTask
//使用resume方法启动任务
dataTask.resume()
}
// 在访问资源的时候,如果服务器返回需要授权(提供一个NSURLCredential对象)
// 那么该方法就回被调用(这个是NSURLSessionDelegate代理方法)
func URLSession(session: NSURLSession,
didReceiveChallenge challenge: NSURLAuthenticationChallenge,
completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?)
-> Void) {
//认证服务器(这里不使用服务器证书认证,只需地址是我们定义的几个地址即可信任)
if challenge.protectionSpace.authenticationMethod
== NSURLAuthenticationMethodServerTrust
&& self.selfSignedHosts.contains(challenge.protectionSpace.host) {
print("服务器认证!")
let credential = NSURLCredential(forTrust:
challenge.protectionSpace.serverTrust!)
credential.certificates
completionHandler(.UseCredential, credential)
}
//认证客户端证书
else if challenge.protectionSpace.authenticationMethod
== NSURLAuthenticationMethodClientCertificate
{
print("客户端证书认证!")
//获取客户端证书相关信息
let identityAndTrust:IdentityAndTrust = self.extractIdentity();
let urlCredential:NSURLCredential = NSURLCredential(
identity: identityAndTrust.identityRef,
certificates: identityAndTrust.certArray as? [AnyObject],
persistence: NSURLCredentialPersistence.ForSession);
completionHandler(.UseCredential, urlCredential);
}
// 其它情况(不接受认证)
else {
print("其它情况(不接受认证)")
completionHandler(.CancelAuthenticationChallenge, nil);
}
}
//获取客户端证书相关信息
func extractIdentity() -> IdentityAndTrust {
var identityAndTrust:IdentityAndTrust!
var securityError:OSStatus = errSecSuccess
let path: String = NSBundle.mainBundle().pathForResource("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
// grab the identity
let identityPointer:AnyObject? = certEntry["identity"];
let secIdentityRef:SecIdentityRef = identityPointer as! SecIdentityRef!;
print("(identityPointer) :::: (secIdentityRef)")
// grab the trust
let trustPointer:AnyObject? = certEntry["trust"];
let trustRef:SecTrustRef = trustPointer as! SecTrustRef;
print("(trustPointer) :::: (trustRef)")
// grab the cert
let chainPointer:AnyObject? = certEntry["chain"];
identityAndTrust = IdentityAndTrust(identityRef: secIdentityRef,
trust: trustRef, certArray: chainPointer!);
}
}
return identityAndTrust;
}
}
//定义一个结构体,存储认证相关信息
struct IdentityAndTrust {
var identityRef:SecIdentityRef
var trust:SecTrustRef
var certArray:AnyObject
}
茶杯头甜蜜终章dlc 官方手机版v1.0.0.3
下载火柴人传说暗影格斗内置菜单 最新版v3.0.1
下载荒野乱斗测试服 安卓版v61.10.3
下载荒野乱斗彩虹服 安卓版v61.10.3
下载寒霜启示录 安卓版v1.25.10
寒霜启示录是一款生存模拟游戏,不少玩家可能对于末日都有着自己
末日城堡免广告版 安卓最新版v0.7.1
末日城堡免广告版是一款非常好玩的模拟经营类游戏,内部可以不看
甜蜜人生模拟器 最新版v1.4.5
甜蜜人生模拟器是一款非常好玩的模拟恋爱手游,玩家在这里能够对
武器锻造师内置功能菜单 v10.4
武器锻造师内置菜单版是游戏的破解版本,在该版本中为玩家提供了
开放空间overfield 安卓版v1.0.5
开放空间Overfield是一款箱庭养成经营手游,让你在广阔