详解iOS开发 - 用AFNetworking实现https单向验证,双向验证

2020-01-18 18:52:58于海丽

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内的设置,这是和上面一样的:

ios开发,单向https,ios,https双向验证,os,https双向认证

3)这里可不需要修改类里面的代码,但是这里需要重写一个方法:


 NSString *url = @"https://www.easck.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;
  }];