iOS适配https详解
马上就要元旦了,网上流传元旦之后苹果会对所有的app进行https的验证,据说会拒绝所有没有使用https的app。但是后来又听说是我们开发者误解了,元旦过后还是会支持http,不过开发者需要说明为什么不用https。不过躲得过初一躲不过十五,还是早点适配https好些啊。然后弄了几天找了好多博客和文档,才暂时解决了这个问题。所谓https,只不过是在http的基础上增加了ssl层的验证(这样说不是很准确),也就是在原来的数据包的基础上加密了一下,然而加密的工作不需要我们开发者来做,只需在对的位置做好证书的验证就行了。其实我对ssl层理解也不深,想着以后有时间一定要把网络这一块掌握,不然下次碰到这种问题还是不好解决。废话不多说,还是先看看代码吧。
首先是对NSURLConnection的适配,不管是原生的还是AF的,归根结底都是要用它去连接服务器。
1.如果使用AF进行网络数据请求,那么使用如下方法即可:
 - (AFSecurityPolicy*)customSecurityPolicy
 {
     //先导入证书
     //在这加证书,一般情况适用于单项认证
     NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ailian" ofType:@"cer"];//证书的路径
     NSData *certData = [NSData dataWithContentsOfFile:cerPath];
     if (certData==nil) {
         return nil;
     }
     // AFSSLPinningModeCertificate 使用证书验证模式
     AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
     // allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
     // 如果是需要验证自建证书,需要设置为YES
     securityPolicy.allowInvalidCertificates = YES;
     //validatesDomainName 是否需要验证域名,默认为YES;
     //假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
     //置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
     //如置为NO,建议自己添加对应域名的校验逻辑。
     securityPolicy.validatesDomainName = NO;
     securityPolicy.pinnedCertificates = @[certData];
     return securityPolicy;
 }
其实,在这里不需要使用服务器的证书,本人亲测过。不过为了保险起见还是加上,还需要注意一点,AF3.0需要用到der格式的证书。
然后加上下面的代码:
_manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:[self getHostURL]]];
[_manager setSecurityPolicy:[self customSecurityPolicy]];
2.如果是原生的NSURLConnection,那么需要在NSURLConnectionDelegate的一个方法里面加代码,如下:
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
//导入证书 NSLog(@"thePath===========%@",thePath);
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data; SecIdentityRef identity = NULL;
// extract the ideneity from the certificate
[self extractP12Data:inPKCS12Data toIdentity:&identity]; SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate); const void *certs[] = {certificate};
// CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
// create a credential from the certificate and ideneity, then reply to the challenge with the credential
//NSLog(@"identity=========%@",identity);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:nil persistence:NSURLCredentialPersistencePermanent]; // credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent]; [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
接下来是对NSURLSession的适配,现在公认更好的网络请求类,支持后台的数据下载和上传,而且自身是安全的。然而,在使用NSURLSession时需要在一个代理方法里配置ssl证书。如下:
- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
NSString *method = challenge.protectionSpace.authenticationMethod;
if([method isEqualToString:NSURLAuthenticationMethodServerTrust]){
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
return;
}
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(PKCS12Data);
SecIdentityRef identity;
// 读取p12证书中的内容
OSStatus result = [self extractP12Data:inPKCS12Data toIdentity:&identity];
if(result != errSecSuccess){
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
return;
}
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, , NULL);
NSURLCredential *credential1 = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)CFBridgingRelease(certArray) persistence:NSURLCredentialPersistencePermanent];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential1);
}
 - (OSStatus) extractP12Data:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity {
     OSStatus securityError = errSecSuccess;
     CFStringRef password = CFSTR("clientepass");
     const void *keys[] = { kSecImportExportPassphrase };
     const void *values[] = { password };
     CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, , NULL, NULL);
     CFArrayRef items = CFArrayCreate(NULL, , , NULL);
     securityError = SecPKCS12Import(inP12Data, options, &items);
     if (securityError == ) {
         CFDictionaryRef ident = (CFDictionaryRef)CFArrayGetValueAtIndex(items,);
         const void *tempIdentity = NULL;
         tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
         *identity = (SecIdentityRef)tempIdentity;
     }
     if (options) {
         CFRelease(options);
     }
     return securityError;
 }
其实适配https没有我们想象的那么复杂,你找对了地方可能几分钟就弄好了,找不到,可能花几天。不管怎样,最后适配成功还是要感谢网上的一些大神,虽然官网上面也有答案,但毕竟时间不等人,等我研究透彻,估计苹果又会有新的东西出来吧。至此,希望能帮到正在为https适配而忧伤的小伙伴们。
iOS适配https详解的更多相关文章
- 了解iOS消息推送一文就够:史上最全iOS Push技术详解
		本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ... 
- iOS开发者证书-详解
		iOS开发者证书-详解/生成/使用 本文假设你已经有一些基本的Xcode开发经验, 并注册了iOS开发者账号. 相关基础 加密算法 现代密码学中, 主要有两种加密算法: 对称密钥加密 和 公开密钥加密 ... 
- 基于rem的移动端响应式适配方案(详解)    移动端H5页面的设计稿尺寸大小规范
		基于rem的移动端响应式适配方案(详解) : https://www.jb51.net/article/118067.htm 移动端H5页面的设计稿尺寸大小规范 http://www.tuyiyi.c ... 
- 公钥与私钥,HTTPS详解
		1.公钥与私钥原理1)鲍勃有两把钥匙,一把是公钥,另一把是私钥2)鲍勃把公钥送给他的朋友们----帕蒂.道格.苏珊----每人一把.3)苏珊要给鲍勃写一封保密的信.她写完后用鲍勃的公钥加密,就可以达到 ... 
- 转载]IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本 )
		原文地址:IOS LBS功能详解[0](获取经纬度)[1](获取当前地理位置文本作者:佐佐木小次郎 因为最近项目上要用有关LBS的功能.于是我便做一下预研. 一般说来LBS功能一般分为两块:一块是地理 ... 
- iOS中-Qutarz2D详解及使用
		在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ... 
- iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)
		前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ... 
- iOS开发——Block详解
		iOS开发--Block详解 1. Block是什么 代码块 匿名函数 闭包--能够读取其他函数内部变量的函数 函数变量 实现基于指针和函数指针 实现回调的机制 Block是一个非常有特色的语法,它可 ... 
- iOS开发:详解Objective-C runTime
		Objective-C总Runtime的那点事儿(一)消息机制 最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎 ... 
随机推荐
- C语言初学者代码中的常见错误与瑕疵(23)
			见:C语言初学者代码中的常见错误与瑕疵(23) 
- DELPHI XE5 与SQLITE
			最近一次使用DELPHI做项目是使用DELPHI2009,为了访问本地数据库方便,使用ACCESS数据库,不需要安装驱动,(WINDOWS自带),但是ACCESS数据库的性能确实很糟糕,通过ADO连接 ... 
- spring @condition 注解
			spring @condition注解是用来在不同条件下注入不同实现的 demo如下: package com.foreveross.service.weixin.test.condition; im ... 
- uboot命令
			uboot是怎么启动kernel的呢? 先熟悉一下uboot的命令吧. 首先是md, 查看内存. OpenJTAG> md 000000000: ea000014 e59ff014 e59ff0 ... 
- 搭建基于Jenkins salt-api的运维工具
			1. 安装salt-master和salt-minion 安装过程不再赘述,请参考http://docs.saltstack.com/en/latest/topics/installation/ind ... 
- Dynamics AX 2012 R2 业务系列-销售业务流程
			在博文Dynamics AX R2 业务系列中,Reinhard对这个系列做了一个规划,下面我们就按照规划开始说业务吧. 1.销售的主要职责 其实这里说的职责主要是针对销售文员,并非整天外面满世界跑业 ... 
- UITableView heightForHeaderInSection遇到的坑
			出现这种现象只需要把 heightforfoot改为0.01 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSectio ... 
- C#利用反射机制创建对象
			"反射"其实就是利用程序集的元数据信息. 反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间. 1.假设你要反射一个 DLL 中的类,并且没有引用 ... 
- java反射类内容获取
			private void DtoReflect(Object obj, MqDto mqDto) throws Exception { Map map = getMap(mqDto); if(obj= ... 
- WEB前端html基础中的各类标签介绍
			2:html中有很多标签,这里列举十几种标签,有它们的用法及在使用过程中的注意事项! 
