当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS之Https自签名证书认证及数据请求的封装原理

iOS之Https自签名证书认证及数据请求的封装原理

2019年07月24日  | 移动技术网IT编程  | 我要评论

天水师范学院是几本,73岁老太遭马蜂袭击死亡,神武飞鱼湖

摘要: 在wwdc 2016开发者大会上,苹果宣布了一个最后期限:到2017年1月1日 app store中的所有应用都必须启用 app transport security安全功能。app transport security(ats)是苹果在ios 9中引入的一项隐私保护功能,屏蔽明文http资源加载,连接必须经过更安全的https。苹果目前允许开发者暂时关闭ats,可以继续使用http连接,但到年底所有官方商店的应用都必须强制性使用ats。

项目中使用的框架是afnetworking 3.0及以上版本,由于ats的原因,ios只允许使用https开头的链接,在2016年12月30日以前苹果允许绕开ats,如下图所示:

但是从2017年1月1日开始将不再接受使用http加载资源的应用,因此本篇文章主要讲解如何使用afn进行自签名证书的通过认证(注:对于使用ca机构认证的证书不需要进行认证,直接使用https开头的链接进行数据访问和加载页面即可)项目已经上传至github(需要参考源码的话请点击链接):

1,建立一个根类 此处命名为aknetpackegeafn

 1>  .h文件 ,创建所需要的get 与 post 方法

#import <foundation/foundation.h>


typedef enum{
  
  aknetworkget ,  /**< get请求 */
  aknetworkpost = 1 /**< post请求 */
}aknetworktype;
typedef void (^httpsuccess)(id json);
typedef void (^httperro)(nserror* error);
@interface aknetpackegeafn : nsobject

+(instancetype)sharehttpmanager;

/*
 *
 networktype:请求方式 get 或 post
 signature:是否使用签名证书,是的话直接写入证书名字,否的话填nil
 api:请求的url接口
 parameters:请求参数
 sucess:请求成功时的返回值
 fail:请求失败时的返回值
 *
 */

- (void)networktype:(aknetworktype)networktype signature:(nsstring *)signature api:(nsstring *)api parameters:(nsdictionary *)parameters success:(httpsuccess)sucess fail:(httperro)fail;

@end

2> .m文件,导入头文件afnetworking.h 新建manager 属性并实现sharehttpmanager类方法

#import "aknetpackegeafn.h"
#import "afnetworking.h"

@interface aknetpackegeafn()

@property (nonatomic,strong) afhttpsessionmanager *manager;

@end

@implementation aknetpackegeafn


+(instancetype)sharehttpmanager{
  static dispatch_once_t onece = 0;
  static aknetpackegeafn *httpmanager = nil;
  dispatch_once(&onece, ^(void){
    httpmanager = [[self alloc]init];
  });
  return httpmanager;
}

2,get 与post 方法的实现

使用时将后台所给的证书转换为 .cer格式 拖入项目根目录中,在方法中进行绑定即可例如后台给的证书名为:kuture.crt  收到证书后双击进行安装,然后打开钥匙串,将名为kuture的证书右击导出,选择后缀为.cer 然后确定即可 如下图所示:

  -->     -->

-->

get 与 post 实现方法的封装

- (void)networktype:(aknetworktype)networktype signature:(nsstring *)signature api:(nsstring *)api parameters:(nsdictionary *)parameters success:(httpsuccess)sucess fail:(httperro)fail{
  
  //开启证书验证模式
  afsecuritypolicy *securitypolicy = [afsecuritypolicy policywithpinningmode:afsslpinningmodecertificate];
  
  //是否允许使用自签名证书
  signature == nil ? (void)(securitypolicy.allowinvalidcertificates = no):(securitypolicy.allowinvalidcertificates = yes);
  
  //是否需要验证域名
  securitypolicy.validatesdomainname = no;
  
  _manager = [[afhttpsessionmanager alloc]initwithbaseurl:[nsurl urlwithstring:api]];
  _manager.responseserializer = [afjsonresponseserializer serializer];
  _manager.securitypolicy = securitypolicy;
  _manager.responseserializer.acceptablecontenttypes = [nsset setwithobjects:@"application/json",@"application/xml",@"text/xml",@"text/json",@"text/plain",@"text/javascript",@"text/html", nil];
  
  if (signature != nil){
    
    __weak typeof(self) weakself = self;
    [_manager setsessiondidreceiveauthenticationchallengeblock:^nsurlsessionauthchallengedisposition(nsurlsession *session, nsurlauthenticationchallenge *challenge, nsurlcredential *__autoreleasing *_credential) {
      
      //获取服务器的 trust object
      sectrustref servertrust = [[challenge protectionspace] servertrust];
      
      //导入自签名证书
      nsstring *cerpath = [[nsbundle mainbundle] pathforresource:@"你的证书名字" oftype:@"cer"];
      nsdata *cerdata = [nsdata datawithcontentsoffile:cerpath];
      
      if (!cerdata) {
        
        nslog(@"==== .cer file is nil ====");
        
        return 0;
      }
      
      nsarray *cerarray = @[cerdata];
      weakself.manager.securitypolicy.pinnedcertificates = cerarray;
      seccertificateref caref = seccertificatecreatewithdata(null, (__bridge cfdataref)cerdata);
      nscassert(caref != nil, @"caref is nil");
      
      nsarray *caarray = @[(__bridge id)(caref)];
      nscassert(caarray != nil, @"caarray is nil");
      
      //将读取到的证书设置为servertrust的根证书
      osstatus status = sectrustsetanchorcertificates(servertrust, (__bridge cfarrayref)caarray);
      sectrustsetanchorcertificatesonly(servertrust, no);
      nscassert(errsecsuccess == status, @"sectrustsetanchorcertificates failed");
      
      //选择质询认证的处理方式
      nsurlsessionauthchallengedisposition disposition = nsurlsessionauthchallengeperformdefaulthandling;
      __autoreleasing nsurlcredential *credential = nil;
      
      //nsurlauthenticationmethodservertrust质询认证方式
      if ([challenge.protectionspace.authenticationmethod isequaltostring:nsurlauthenticationmethodservertrust]) {
        //基于客户端的安全策略来决定是否信任该服务器,不信任则不响应质询
        if ([weakself.manager.securitypolicy evaluateservertrust:challenge.protectionspace.servertrust fordomain:challenge.protectionspace.host]) {
          
          //创建质询证书
          credential = [nsurlcredential credentialfortrust:challenge.protectionspace.servertrust];
          
          //确认质询方式
          if (credential) {
            disposition = nsurlsessionauthchallengeusecredential;
            
          } else {
            
            disposition = nsurlsessionauthchallengeperformdefaulthandling;
          }
          
        } else {
          
          //取消挑战
          disposition = nsurlsessionauthchallengecancelauthenticationchallenge;
        }
        
      } else {
        
        disposition = nsurlsessionauthchallengeperformdefaulthandling;
      }
      
      return disposition;
    }];
  }
  
  if (networktype == 0){
    
    [_manager get:api parameters:parameters progress:^(nsprogress * _nonnull uploadprogress) {
    } success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) {
      
      if (sucess){
        
        sucess(responseobject);
      }else{
        
        nslog(@"链接异常或网络不存在");
      }
    } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) {
      
      fail(error);
    }];

  }else if (networktype == 1){
    
    
    [_manager post:api parameters:parameters progress:^(nsprogress * _nonnull uploadprogress) {
    } success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) {
      
      if (sucess){
        
        sucess(responseobject);
      }else{
        
        nslog(@"链接异常或网络不存在");
      }
    } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) {
      
      fail(error);
    }];

  }  
}

2  使用方法,在需要进行数据获取或传递的类里面,直接导入头文件 aknetpackegeafn.h ,并实现方法即可,如下所示:

//创建对象
  //如果是自签名证书,使用前先到aknetpackegeafn相应的方法里进行证书的绑定(证书直接拖入项目中)即可
  /*
   *
   networktype:请求方式 get 或 post
   signature:是否使用签名证书,是的话直接写入证书名字,否的话填nil
   api:请求的url接口
   parameters:请求参数
   sucess:请求成功时的返回值
   fail:请求失败时的返回值
   *
   */
  
  aknetpackegeafn *nethttps = [aknetpackegeafn sharehttpmanager];
  [nethttps networktype:请求类型 signature:证书名称 api:请求url parameters:参数 success:^(id json) {
    
    nslog(@"json:%@",json);
  } fail:^(nserror *error) {
    
    nslog(@"error:%@",error);
  }];

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网