记的同时在 “工程” -> “Build Phases” -> “Copy Bundle Resources” 中添加这两个证书文件。
2,配置Info.plist由于我们使用的是自签名的证书,而苹果ATS(App Transport Security)只信任知名CA颁发的证书,所以在iOS9下即使是HTTPS请求还是会被ATS拦截。所以在Info.plist下添加如下配置(iOS8不需要):| 12345 | <key>NSAPPTransportSecurity</key><dict> <key>NSAllowsArbitraryLoads</key> <true/></dict> |
| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 | import UIKitimport Alamofire class ViewController: UIViewController{ overridefunc viewDidLoad() { super.viewDidLoad() //认证相关设置 letmanager = SessionManager.default manager.delegate.sessionDidReceiveChallenge = { session, challengein //认证服务器证书 ifchallenge.PRotectionSpace.authenticationMethod ==NSURLAuthenticationMethodServerTrust { print("服务端证书认证!") letserverTrust:SecTrust= challenge.protectionSpace.serverTrust! letcertificate = SecTrustGetCertificateAtIndex(serverTrust, 0)! letremoteCertificateData =CFBridgingRetain(SecCertificateCopyData(certificate))! letcerPath = Bundle.main.path(forResource:"tomcat", ofType:"cer")! letcerUrl = URL(fileURLWithPath:cerPath) letlocalCertificateData = try! Data(contentsOf: cerUrl) if(remoteCertificateData.isEqual(localCertificateData) ==true) { letcredential = URLCredential(trust: serverTrust) challenge.sender?.use(credential,for: challenge) return(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!)) }else { return(.cancelAuthenticationChallenge, nil) } } //认证客户端证书 elseif challenge.protectionSpace.authenticationMethod ==NSURLAuthenticationMethodClientCertificate{ print("客户端证书认证!") //获取客户端证书相关信息 letidentityAndTrust:IdentityAndTrust= self.extractIdentity(); leturlCredential:URLCredential= URLCredential( identity: identityAndTrust.identityRef, certificates: identityAndTrust.certArrayas? [AnyObject], persistence:URLCredential.Persistence.forSession); return(.useCredential, urlCredential); } // 其它情况(不接受认证) else{ print("其它情况(不接受认证)") return(.cancelAuthenticationChallenge, nil) } } //数据请求 Alamofire.request("https://192.168.1.112:8443") .responseString { responsein print(response) } } //获取客户端证书相关信息 funcextractIdentity() -> IdentityAndTrust{ varidentityAndTrust:IdentityAndTrust! varsecurityError:OSStatus= errSecSuccess letpath: String = Bundle.main.path(forResource:"mykey", ofType:"p12")! letPKCS12Data = NSData(contentsOfFile:path)! letkey : NSString= kSecImportExportPassphrase asNSString letoptions : NSDictionary= [key : "123456"]//客户端证书密码 //create variable for holding security information //var privateKeyRef: SecKeyRef? = nil varitems : CFArray? securityError =SecPKCS12Import(PKCS12Data, options, &items) ifsecurityError == errSecSuccess { letcertItems:CFArray= items as CFArray!; letcertItemsArray:Array= certItems asArray letdict:AnyObject? = certItemsArray.first; iflet certEntry:Dictionary= dict as?Dictionary<String,AnyObject> { // grab the identity letidentityPointer:AnyObject? = certEntry["identity"]; letsecIdentityRef:SecIdentity= identityPointer as!SecIdentity! print("/(identityPointer) :::: /(secIdentityRef)") // grab the trust lettrustPointer:AnyObject? = certEntry["trust"] lettrustRef:SecTrust= trustPointer as!SecTrust print("/(trustPointer) :::: /(trustRef)") // grab the cert letchainPointer:AnyObject? = certEntry["chain"] identityAndTrust =IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: chainPointer!) } } returnidentityAndTrust; } overridefunc didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }} //定义一个结构体,存储认证相关信息structIdentityAndTrust { varidentityRef:SecIdentity vartrust:SecTrust varcertArray:AnyObject} |
4,只使用一个客户端证书由于我们使用的是自签名的证书,那么对服务器的认证全由客户端这边判断。也就是说其实使用一个客户端证书“mykey.p12”也是可以的(项目中也只需导入一个证书)。当对服务器进行验证的时候,判断服务主机地址是否正确,是的话信任即可(代码高亮部分)| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 | import UIKitimport Alamofire class ViewController: UIViewController{ //自签名网站地址 letselfSignedHosts = ["192.168.1.112","www.hangge.com"] overridefunc viewDidLoad() { super.viewDidLoad() //认证相关设置 letmanager = SessionManager.default manager.delegate.sessionDidReceiveChallenge = { session, challengein //认证服务器(这里不使用服务器证书认证,只需地址是我们定义的几个地址即可信任) ifchallenge.protectionSpace.authenticationMethod ==NSURLAuthenticationMethodServerTrust &&self.selfSignedHosts.contains(challenge.protectionSpace.host) { print("服务器认证!") letcredential = URLCredential(trust: challenge.protectionSpace.serverTrust!) return(.useCredential, credential) } //认证客户端证书 elseif challenge.protectionSpace.authenticationMethod ==NSURLAuthenticationMethodClientCertificate{ print("客户端证书认证!") //获取客户端证书相关信息 letidentityAndTrust:IdentityAndTrust= self.extractIdentity(); leturlCredential:URLCredential= URLCredential( identity: identityAndTrust.identityRef, certificates: identityAndTrust.certArrayas? [AnyObject], persistence:URLCredential.Persistence.forSession); return(.useCredential, urlCredential); } // 其它情况(不接受认证) else{ print("其它情况(不接受认证)") return(.cancelAuthenticationChallenge, nil) } } //数据请求 Alamofire.request("https://192.168.1.112:8443") .responseString { responsein print(response) } } //获取客户端证书相关信息 funcextractIdentity() -> IdentityAndTrust{ varidentityAndTrust:IdentityAndTrust! varsecurityError:OSStatus= errSecSuccess letpath: String = Bundle.main.path(forResource:"mykey", ofType:"p12")! letPKCS12Data = NSData(contentsOfFile:path)! letkey : NSString= kSecImportExportPassphrase asNSString letoptions : NSDictionary= [key : "123456"]//客户端证书密码 //create variable for holding security information //var privateKeyRef: SecKeyRef? = nil varitems : CFArray? securityError =SecPKCS12Import(PKCS12Data, options, &items) ifsecurityError == errSecSuccess { letcertItems:CFArray= items as CFArray!; letcertItemsArray:Array= certItems asArray letdict:AnyObject? = certItemsArray.first; iflet certEntry:Dictionary= dict as?Dictionary<String,AnyObject> { // grab the identity letidentityPointer:AnyObject? = certEntry["identity"]; letsecIdentityRef:SecIdentity= identityPointer as!SecIdentity! print("/(identityPointer) :::: /(secIdentityRef)") // grab the trust lettrustPointer:AnyObject? = certEntry["trust"] lettrustRef:SecTrust= trustPointer as!SecTrust print("/(trustPointer) :::: /(trustRef)") // grab the cert letchainPointer:AnyObject? = certEntry["chain"] identityAndTrust =IdentityAndTrust(identityRef: secIdentityRef, trust: trustRef, certArray: chainPointer!) } } returnidentityAndTrust; } overridefunc didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }} //定义一个结构体,存储认证相关信息structIdentityAndTrust { varidentityRef:SecIdentity vartrust:SecTrust varcertArray:AnyObject} |
新闻热点
疑难解答