亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解iOS開發(fā) - 用AFNetworking實現(xiàn)https單向驗證,雙向驗證

 更新時間:2016年12月20日 10:44:41   作者:CodingFire  
這篇文章主要介紹了詳解iOS開發(fā) - 用AFNetworking實現(xiàn)https單向驗證,雙向驗證,具有一定的參考價值,感興趣的小伙伴們可以參考一下。

自蘋果宣布2017年1月1日開始強制使用https以來,htpps慢慢成為大家討論的對象之一,不是說此前https沒有出現(xiàn),只是這一決策讓得開發(fā)者始料未及,博主在15年的時候就做過https的接口,深知此坑之深,原因就是自身對這方面知識不了解加上網上的資料少,除此外還有博客不知對錯就互相轉載,導致當時網上幾乎找不到能用的代碼,這一點,博主說的毫不夸張。

鑒于此,博主一直想填一下這個坑,多增加一些正確的代碼,來供廣大開發(fā)者使用,后來一直被擱置,經過嘗試后,博主現(xiàn)將整理好的代碼發(fā)布在這里,希望能幫到焦急尋找的開發(fā)者。

1.先來說說老的AFNetworking2.x怎么來實現(xiàn)的

博主在網上看過幾篇帖子,其中說的一些方法是正確的,但是卻并不全對,由于那幾篇博客幾乎一樣,博主不能確定最早的那篇是誰寫的,所以就重新在下面說明下方法:

1)倒入client.p12證書;

2)在plist文件做如圖配置:

3)在AFNetworking中修改一個類:

找到這個文件,在里面增加一個方法:

- (OSStatus)extractIdentity:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity { 
  OSStatus securityError = errSecSuccess;
  CFStringRef password = CFSTR("證書密碼"); 
  const void *keys[] = { kSecImportExportPassphrase };
  const void *values[] = { password };
  CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
  CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
  securityError = SecPKCS12Import(inP12Data, options, &items);
  if (securityError == 0)   
  {
    CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0); 
    const void *tempIdentity = NULL; 
    tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
    *identity = (SecIdentityRef)tempIdentity;  
  } 
  if (options) {  
    CFRelease(options);  
  }
  return securityError;
}

再修改一個方法:

用下面的這段代碼替換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 extractIdentity :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];

}

4)發(fā)起請求

 NSString *url = @"xxxxxxxxxx";
  // 1.獲得請求管理者
  AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
  //2設置https 請求
  AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
  securityPolicy.allowInvalidCertificates = YES;
  mgr.securityPolicy = securityPolicy;
  // 3.發(fā)送POST請求

  [mgr POST:url parameters:nil success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) {
    NSLog(@"responseObject: %@", responseObject);

  } failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
    NSLog(@"Error: %@", error);

  }];

到此,老版的AFNetworking請求https接口的雙向驗證就做完了,但是有一個問題,這里需要改動AFNetworking的代碼,何況新的AFNetworking已經有了,為了保持代碼的活力,老的應該摒棄的,而且更新pods后肯定替換的代碼就沒了,也是一個問題,不要急,下面來說說怎么用新的AFNetworking,并解決被pods更新替換代碼的問題。

最后再說一點,使用老的AF來請求,只用到了client.p12文件,并沒有用到server.cer,在新的里面是有用到的,猜測可能是客戶端選擇信任任何證書導致的,就變成了單向的驗證。

Demo放在最后

2.來說說新的AFNetworking3.x怎么來實現(xiàn)的

1)倒入client.p12和server.cer文件

2)plist內的設置,這是和上面一樣的:

3)這里可不需要修改類里面的代碼,但是這里需要重寫一個方法:

 NSString *url = @"https://test.niuniuhaoguanjia.com/3.0.0/?service=City.GetCityList";

  NSString *certFilePath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
  NSData *certData = [NSData dataWithContentsOfFile:certFilePath];
  NSSet *certSet = [NSSet setWithObject:certData];
  AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:certSet];
  policy.allowInvalidCertificates = YES;
  policy.validatesDomainName = NO;

  _manager = [AFHTTPSessionManager manager];
  _manager.securityPolicy = policy;
  _manager.requestSerializer = [AFHTTPRequestSerializer serializer];
  _manager.responseSerializer = [AFHTTPResponseSerializer serializer];
  _manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/plain", nil];
  //關閉緩存避免干擾測試r
  _manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
  [_manager setSessionDidBecomeInvalidBlock:^(NSURLSession * _Nonnull session, NSError * _Nonnull error) {
    NSLog(@"setSessionDidBecomeInvalidBlock");
  }];
  //客戶端請求驗證 重寫 setSessionDidReceiveAuthenticationChallengeBlock 方法
  __weak typeof(self)weakSelf = self;
  [_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) {
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __autoreleasing NSURLCredential *credential =nil;
    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 {
      // client authentication
      SecIdentityRef identity = NULL;
      SecTrustRef trust = NULL;
      NSString *p12 = [[NSBundle mainBundle] pathForResource:@"client"ofType:@"p12"];
      NSFileManager *fileManager =[NSFileManager defaultManager];

      if(![fileManager fileExistsAtPath:p12])
      {
        NSLog(@"client.p12:not exist");
      }
      else
      {
        NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];

        if ([[weakSelf class]extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data])
        {
          SecCertificateRef certificate = NULL;
          SecIdentityCopyCertificate(identity, &certificate);
          const void*certs[] = {certificate};
          CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);
          credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
          disposition =NSURLSessionAuthChallengeUseCredential;
        }
      }
    }
    *_credential = credential;
    return disposition;
  }];

4)發(fā)起請求

//第三步和這一步代碼是放在一起的,請注意哦
  [_manager GET:url parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {

  } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
    NSLog(@"JSON: %@", dic);
  } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSLog(@"Error: %@", error);

    NSData *data = [error.userInfo objectForKey:@"com.alamofire.serialization.response.error.data"];
    NSString *str = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",str);
  }];

另外還要加上一個方法:

+(BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
  OSStatus securityError = errSecSuccess;
  //client certificate password
  NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"證書密碼"
                                 forKey:(__bridge id)kSecImportExportPassphrase];

  CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
  securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);

  if(securityError == 0) {
    CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0);
    const void*tempIdentity =NULL;
    tempIdentity= CFDictionaryGetValue (myIdentityAndTrust,kSecImportItemIdentity);
    *outIdentity = (SecIdentityRef)tempIdentity;
    const void*tempTrust =NULL;
    tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);
    *outTrust = (SecTrustRef)tempTrust;
  } else {
    NSLog(@"Failedwith error code %d",(int)securityError);
    return NO;
  }
  return YES;
}

沒錯,我們是要封裝一下,可是要怎么封裝呢?博主嘗試了集中都失敗了,真是百思不得解,相信主動去封裝的開發(fā)者也會碰到封裝后請求失敗的問題,也許你成功了,但是這里需要注意一個在block內使用變量的問題,具體的可以去看博主怎么封裝的。

到這里,新的AF請求https就已經結束了,想看封裝的,Demo放在最后。

3.單向驗證

說到這個,不得不說一下網上的很多方法,都把單向驗證當作雙向的,其實也是并不理解其原理,關于原理,請看這里
代碼實現(xiàn)AF都是一樣的:

//AF加上這句和下面的方法
  _manager.securityPolicy = [self customSecurityPolicy];



/**** SSL Pinning ****/
- (AFSecurityPolicy*)customSecurityPolicy {
  NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
  NSData *certData = [NSData dataWithContentsOfFile:cerPath];
  AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
  [securityPolicy setAllowInvalidCertificates:YES];
  NSSet *set = [NSSet setWithObjects:certData, nil];
  [securityPolicy setPinnedCertificates:@[certData]];
  /**** SSL Pinning ****/
  return securityPolicy;
}

4.Demo下載福利

因為證書安全問題,Demo 里的證書博主刪除了,請見諒,請大家放入自己的證書。

老的AF訪問httpsDemo

新的AF訪問httpsDemo

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • IOS提醒用戶重新授權打開定位功能

    IOS提醒用戶重新授權打開定位功能

    這篇文章主要介紹了IOS提醒用戶重新授權打開定位功能的相關資料,需要的朋友可以參考下
    2015-12-12
  • Flutter繪制3.4邊形及多邊形漸變動畫實現(xiàn)示例

    Flutter繪制3.4邊形及多邊形漸變動畫實現(xiàn)示例

    這篇文章主要為大家介紹了Flutter繪制3.4邊形之多邊形漸變動畫實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 一個iOS上的秒表小應用的實現(xiàn)方法分享

    一個iOS上的秒表小應用的實現(xiàn)方法分享

    這篇文章主要介紹了一個iOS上的秒表小應用的實現(xiàn)方法分享,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下
    2015-10-10
  • IOS實現(xiàn)上滑隱藏NvaigtionBar而下拉則顯示效果

    IOS實現(xiàn)上滑隱藏NvaigtionBar而下拉則顯示效果

    這篇文章給大家介紹了如何實現(xiàn)APP上滑時隱藏navigationBar而下拉則又會顯示,雖然也是隱藏但是效果和其他完全不一樣,因為以前沒做過所以試著去實現(xiàn)一下,現(xiàn)在分享給大家,有需要的可以參考借鑒。
    2016-09-09
  • iOS 中事件的響應鏈和傳遞鏈

    iOS 中事件的響應鏈和傳遞鏈

    iOS事件鏈有兩條:事件的響應鏈;Hit-Testing事件的傳遞鏈。這篇文章主要介紹了iOS 中事件的響應鏈和傳遞鏈,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • 深入理解iOS的狀態(tài)欄

    深入理解iOS的狀態(tài)欄

    這篇文章給大家分別介紹了iOS狀態(tài)欄隱藏的兩種方法、狀態(tài)欄樣式、背景色以及狀態(tài)欄的應用,有需要的朋友們可以參考借鑒,下面來一起看看吧。
    2016-09-09
  • iOS中searchBar(搜索框)光標初始位置后移

    iOS中searchBar(搜索框)光標初始位置后移

    這篇文章主要介紹了iOS中searchBar(搜索框)光標初始位置后移的關鍵代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-08-08
  • iOS App使用SQLite之句柄的定義及數(shù)據庫的基本操作

    iOS App使用SQLite之句柄的定義及數(shù)據庫的基本操作

    SQLite中在定義過句柄之后就可以指向數(shù)據庫,從而利用iOS應用程序進行打開或關閉等各種操作,這里我們就來看一下iOS App使用SQLite之句柄的定義及數(shù)據庫的基本操作
    2016-06-06
  • iOS中遍歷的方法總結

    iOS中遍歷的方法總結

    本篇文章主要介紹了iOS中遍歷的方法總結,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • iOS圖片界面翻頁切換效果

    iOS圖片界面翻頁切換效果

    這篇文章主要為大家詳細介紹了iOS圖片界面翻頁切換效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11

最新評論