首页 > 学院 > 开发设计 > 正文

Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用

2019-11-09 14:13:19
字体:
来源:转载
供稿:网友
(本文代码已升级至Swift3) 我原来写过一篇文章介绍如何使用证书通过SSL/TLS方式进行网络请求(Swift - 使用URLsession通过HTTPS进行网络请求,及证书的使用),当时用的是URLSession。本文介绍如何使用 Alamofire 来实现HTTPS网络请求,由于Alamofire就是对URLSession的封装,所以实现起来区别不大。(如果Alamofire的配置使用不了解的,可以先去看看我原来写的文章:Swift - HTTP网络操作库Alamofire使用详解)一,证书的生成,以及服务器配置参考我前面写的这篇文章:Tomcat服务器配置https双向认证(使用keytool生成证书)文章详细介绍了HTTPS,SSL/TLS。还有使用key tool生成自签名证书,Tomcat下https服务的配置。二,Alamofire使用HTTPS进行网络请求1,证书导入前面文章介绍了通过客户端浏览器访问HTTPS服务需,需要安装“mykey.p12”,“tomcat.cer”这两个证书。同样,我们开发的应用中也需要把这两个证书添加进来。原文:Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用记的同时在 “工程” -> “Build Phases” -> “Copy Bundle Resources” 中添加这两个证书文件。原文:Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用2,配置Info.plist由于我们使用的是自签名的证书,而苹果ATS(App Transport Security)只信任知名CA颁发的证书,所以在iOS9下即使是HTTPS请求还是会被ATS拦截。所以在Info.plist下添加如下配置(iOS8不需要):
12345<key>NSAPPTransportSecurity</key><dict>    <key>NSAllowsArbitraryLoads</key>    <true/></dict>
3,使用两个证书进行双向验证,以及网络请求
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111import 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}
控制台打印输出如下:原文:Swift - 使用Alamofire通过HTTPS进行网络请求,及证书的使用4,只使用一个客户端证书由于我们使用的是自签名的证书,那么对服务器的认证全由客户端这边判断。也就是说其实使用一个客户端证书“mykey.p12”也是可以的(项目中也只需导入一个证书)。当对服务器进行验证的时候,判断服务主机地址是否正确,是的话信任即可(代码高亮部分)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899import 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}

原文出自:www.hangge.com  转载请保留原文链接:http://www.hangge.com/blog/cache/detail_1052.html
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表