亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

詳解iOS開發 - 用AFNetworking實現https單向驗證,雙向驗證

2020-07-26 03:01:33
字體:
來源:轉載
供稿:網友

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

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

1.先來說說老的AFNetworking2.x怎么來實現的

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

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 *)connectionwillSendRequestForAuthenticationChallenge:(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)發起請求

 NSString *url = @"xxxxxxxxxx";  // 1.獲得請求管理者  AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];  //2設置https 請求  AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];  securityPolicy.allowInvalidCertificates = YES;  mgr.securityPolicy = securityPolicy;  // 3.發送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怎么來實現的

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)發起請求

//第三步和這一步代碼是放在一起的,請注意哦  [_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;}

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

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

3.單向驗證

說到這個,不得不說一下網上的很多方法,都把單向驗證當作雙向的,其實也是并不理解其原理,關于原理,請看這里
代碼實現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

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美高清在线视频观看不卡| 国产精品一久久香蕉国产线看观看| 亚洲在线视频观看| 国产精品wwww| 亚洲性生活视频在线观看| 精品国产一区二区在线| 日本精品va在线观看| 国产日韩av高清| 国产精品1区2区在线观看| 97国产精品免费视频| 蜜臀久久99精品久久久无需会员| 欧美精品免费在线| 久久精品视频免费播放| 激情久久av一区av二区av三区| 爽爽爽爽爽爽爽成人免费观看| **欧美日韩vr在线| 高潮白浆女日韩av免费看| 亚洲石原莉奈一区二区在线观看| 国产精品日韩在线| 亚洲一区亚洲二区| 日韩av电影手机在线观看| 亚洲福利视频网站| 亚洲精品欧美一区二区三区| 欧美激情第6页| 亚洲国产日韩欧美在线图片| 日韩中文字幕精品| 日本三级韩国三级久久| 日韩电影在线观看永久视频免费网站| 亚洲欧美日韩直播| 日韩有码在线视频| 日韩大片免费观看视频播放| 爽爽爽爽爽爽爽成人免费观看| 亚洲日韩中文字幕| 91久久久久久国产精品| 亚洲欧美国产精品va在线观看| 中文字幕亚洲一区| 色偷偷亚洲男人天堂| 国产日韩视频在线观看| 国产精品96久久久久久| 久久久久久国产精品久久| 国产精品一区二区性色av| 色综合久久88色综合天天看泰| 国产精品国语对白| 中日韩美女免费视频网址在线观看| 北条麻妃一区二区在线观看| 国产一区二区三区在线观看视频| 久久久久亚洲精品成人网小说| 国产高清在线不卡| 欧美日韩国产综合新一区| 亚洲一区二区三区sesese| 亚洲加勒比久久88色综合| 日韩av三级在线观看| 国产日韩亚洲欧美| 日韩av在线导航| 成人午夜高潮视频| 国产专区精品视频| 国产精品成人aaaaa网站| 亚洲黄色片网站| 国语自产在线不卡| 成人午夜一级二级三级| 欧美超级乱淫片喷水| 亚洲乱码一区二区| 亚洲综合在线播放| 国产精品久久久久7777婷婷| 亚洲人成网站777色婷婷| 亚洲天堂网站在线观看视频| 欧美精品日韩三级| 自拍偷拍免费精品| 国产精品美女主播在线观看纯欲| 日韩视频中文字幕| 亚洲成人久久电影| 一本色道久久88精品综合| 一本色道久久88亚洲综合88| 亚洲欧美中文日韩在线v日本| 成人午夜在线视频一区| 疯狂蹂躏欧美一区二区精品| 亚洲va欧美va国产综合久久| 亚洲欧美变态国产另类| 岛国视频午夜一区免费在线观看| 久久色精品视频| 亚洲专区中文字幕| 久久久免费高清电视剧观看| 久久99精品久久久久久青青91| 在线亚洲欧美视频| 欧美亚洲第一页| 欧美亚洲视频在线看网址| 日韩一区二区三区xxxx| 成人精品久久一区二区三区| 国产精品国产三级国产aⅴ浪潮| 国产精品久久久999| 在线观看国产欧美| 国产丝袜精品视频| 成人国产亚洲精品a区天堂华泰| 国产精品电影一区| 91久久久精品| 亚洲欧洲国产一区| 91香蕉亚洲精品| 成人疯狂猛交xxx| 亚洲福利在线观看| 日韩av在线网页| 国产成人精品电影久久久| 91中文字幕一区| 国产成人一区三区| 精品久久久久久久久久久| 欧美日韩国产成人| 中文字幕自拍vr一区二区三区| 欧美风情在线观看| 国产一区二区三区精品久久久| 亚洲国产一区二区三区四区| 中文字幕欧美亚洲| 777午夜精品福利在线观看| 欧美日韩免费一区| 97久久精品在线| 国产91精品久久久久久| 国产精品免费久久久久影院| 久久福利视频网| 一区二区中文字幕| 国产精品一香蕉国产线看观看| 欧日韩不卡在线视频| 日韩中文第一页| 欧美贵妇videos办公室| 国产在线精品播放| 日韩精品视频观看| 黑人巨大精品欧美一区免费视频| 国产精品国产亚洲伊人久久| 亚洲自拍偷拍在线| 91精品久久久久久| 久久久999精品免费| 中文字幕成人精品久久不卡| 在线观看久久久久久| 久久人人爽人人| 97在线视频免费| 亚洲偷熟乱区亚洲香蕉av| 久久久国产视频| 亚洲精品自产拍| 国产一区二区在线播放| 欧美激情视频在线| 亚洲欧美中文日韩在线v日本| 国产精品扒开腿做爽爽爽视频| 色偷偷88888欧美精品久久久| 色偷偷亚洲男人天堂| 国产日产久久高清欧美一区| 欧美日韩性视频在线| 国产欧美一区二区白浆黑人| 亚洲**2019国产| 亚洲男人的天堂网站| 欧美激情久久久| 日本国产高清不卡| 国产激情视频一区| 国产亚洲精品久久| 欧美一区二区三区免费视| 青青久久aⅴ北条麻妃| 欧美亚洲一级片| 日韩av在线电影网| 日韩av免费观影| 精品久久久久久久久久ntr影视| 国产69精品久久久| 国产亚洲精品成人av久久ww| 亚洲精品xxx| 亚洲va电影大全| 久热99视频在线观看| 日韩欧美在线免费| 亚洲成av人片在线观看香蕉| 亚洲欧洲一区二区三区在线观看|