NSURLSession didReceiveChallenge调用每个请求

时间:2017-03-09 13:04:15

标签: ios networking nsurlsession client-certificates

我正在使用此自定义类使用证书从服务器(ASP.NET IIS 7.5)下载数据。它工作得很好,除了每次请求都会调用didReceiveChallenge方法,并且必须一次又一次地应用凭证。表现很糟糕。

我们怎样才能避免这种情况?

感谢。

#import "ServerRequest.h"
#import <UIKit/UIKit.h>

@implementation ServerRequest{           
    NSMutableData * recievedData;
    NSString * operationName;
    NSString * operationParameters;
    DataOperationType operationType;
    NSURL* downloadURL;
    NSData * HTTPBodyData;
    UIView * waitView;
    UIProgressView * progressView;        
}    

- (instancetype)init{        
    if(self = [super init]) {          
    }
    return self;
}

- (NSURLSession *)normalSession{        
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

    NSURLProtectionSpace * protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:[Config getBaseURL] port:443 protocol:@"https" realm:nil authenticationMethod:NSURLAuthenticationMethodClientCertificate];

    [configuration.URLCredentialStorage setDefaultCredential:[Helper getCredential] forProtectionSpace:protectionSpace];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    return session;       
} 

- (instancetype)initWithRequest:(NSString *)request
{
    if(self = [super init]) {
        operationType = DataOperationTypeData;
        downloadURL = [NSURL URLWithString:request];
        NSLog(@"Created download operation for URL: %@", [downloadURL absoluteString]);
    }
    return self;
}

- (instancetype)initWithRequest:(NSString *)request Dicionary:(NSString *) dataDictionary{
    if(self = [super init]) {
        operationType = DataOperationTypeHTMLFrom;
        downloadURL =  [NSURL URLWithString:request];
        NSLog(@"Created download operation for URL: %@", [downloadURL absoluteString]);
        operationParameters = dataDictionary;
             }
    return self;
}

- (instancetype)initWithRequest:(NSString *)request data:(NSData *) bodyData{
    if(self = [super init]) {
        operationType = DataOperationTypeBodyData;
        downloadURL =  [NSURL URLWithString:request];
        NSLog(@"Created download operation for URL: %@", [downloadURL absoluteString]);

        HTTPBodyData = bodyData;           
    }
    return self;
}

- (void) performOperationWithCompletion:(ServerRequestCompletion)onCompletion error:(ServerRequestError)onError{

    if (self.showProgressView){           
        [self configureProgressView];            
    }

    if (self.parentView) {
        waitView = [Config createWaitView:self.parentView];
    }

    self.completion = onCompletion;
    self.error = onError;     

    NSMutableURLRequest *request;
    request = [NSMutableURLRequest requestWithURL:downloadURL];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"utf-8" forHTTPHeaderField:@"Accept-Charset"];

    if (operationType == DataOperationTypeHTMLFrom) {
        NSData *postData = [operationParameters dataUsingEncoding:NSUTF8StringEncoding];

        [request setHTTPMethod:@"POST"];
        [request setValue:@"utf-8" forHTTPHeaderField:@"Accept-Charset"];
        [request setValue:[NSString stringWithFormat:@"%ld", (unsigned long)postData.length] forHTTPHeaderField:@"Content-Length"];
        [request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:postData];                     
    }
    else if (operationType == DataOperationTypeBodyData) {                        
        [request setHTTPMethod:@"POST"];
        [request setValue:[NSString stringWithFormat:@"%ld", (unsigned long)HTTPBodyData.length] forHTTPHeaderField:@"Content-Length"];
        [request addValue: @"multipart/form-data; charset=utf-8" forHTTPHeaderField: @"Content-Type"];
        [request setHTTPBody:HTTPBodyData];                        
    }
    else{
        [request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
     }

    NSURLSession * defaultSession = [self normalSession];

    NSURLSessionTask *  dataTask = [defaultSession dataTaskWithRequest:request];

    if (!dataTask) {
        self.error([EXError errorWithDomain:[[NSBundle mainBundle] bundleIdentifier] code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Could not initialize connection"}]);           
    }else{            
        if (self.showProgressView) {
            dispatch_async(dispatch_get_main_queue(), ^{
              //   AppDelegate_Shared * appDelegate = (AppDelegate_Shared *)([UIApplication sharedApplication]).delegate;
//                [appDelegate.progressView setHidden:NO];
//                [appDelegate.progressView setProgress:0];
            });    
        }
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

        [dataTask resume];                     
    }           
}


- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler{

     //NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
     NSURLCredential *credential = [Helper getCredential];

       if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM])
        {                  
            if (challenge.previousFailureCount  >= 3)
            {                    
                // handle the fact that the previous attempt failed
                EXError* error = [EXError errorWithDomain:NSURLErrorDomain code:403 userInfo: @{NSLocalizedDescriptionKey: @"Unable to verify account information."}];
                [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
                self.error(error);                   
            }else{                
            NSURLCredentialPersistence persistence = NSURLCredentialPersistenceForSession;

            NSString * userName = [Config getUserName];
            NSString * password = [Config getPassword];
            NSURLCredential *loginCredential = [NSURLCredential credentialWithUser:userName password:password persistence:persistence];
            completionHandler(NSURLSessionAuthChallengeUseCredential, loginCredential);
                [self removeWaitView];
            }                
        }
        else if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
        {                
            completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
            //completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
            [self removeWaitView];
        }
        else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate)
        {                   NSLog(@"\n______________________________________________________ Authentication Method Client Certificate _________________________________________________");
                completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
                [self removeWaitView];                
        }
        else{
            completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
            [self removeWaitView];
        }  
}    

-(void) configureProgressView{                        
    UIViewController * topController = [Helper currentTopViewController];

    if (![topController isKindOfClass:[UINavigationController class]]) {
        return;
    }

    UINavigationController * navigationController = (UINavigationController *)topController;

    UINavigationBar * navigationBar = [navigationController navigationBar];

    progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
    progressView.frame = CGRectMake(navigationBar.frame.origin.x, navigationBar.frame.size.height - 5, navigationBar.frame.size.width, 5);

    [navigationBar addSubview:progressView];      
}  

-(void) removeWaitView{
   [waitView removeFromSuperview];
    waitView = nil;
}

- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error{                
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{        
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    NSDictionary *responseHeaders = ((NSHTTPURLResponse *)response).allHeaderFields;

    NSLog(@"headers: %@", responseHeaders.description);

    if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;

        if (httpResponse.statusCode >= 400) { // Client/Server Error
            EXError * error = [EXError errorWithDomain:[[NSBundle mainBundle] bundleIdentifier] code:httpResponse.statusCode userInfo:@{NSLocalizedDescriptionKey: [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]}];

            self.error(error);

           NSLog(@"Failed with Error %ld : %@", (long)httpResponse.statusCode, [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]);
           completionHandler(NSURLSessionResponseAllow);
           [self removeWaitView];
            return;
        }            
    }       
    completionHandler(NSURLSessionResponseAllow);
    [self removeWaitView];
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{

    if (!recievedData) {
        recievedData = [NSMutableData new];
    }

    [recievedData appendData:data];

    if ([dataTask countOfBytesExpectedToReceive] !=NSURLSessionTransferSizeUnknown) {
        double progress =  (double)[dataTask countOfBytesReceived] / (double) [dataTask countOfBytesExpectedToReceive];
        if (self.showProgressView) {
            dispatch_async(dispatch_get_main_queue(), ^{

                [progressView setProgress:progress animated:YES];
            });
        }           
    }       
  //  DLog(@"progress : %lld", [dataTask countOfBytesExpectedToReceive]);        
}


//- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
//   didSendBodyData:(int64_t)bytesSent
//   totalBytesSent:(int64_t)totalBytesSent
//   totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
//   // DLog(@"Did Sent %f", (double)totalBytesSent);
//    
//    if (self.showProgressView) {
//        
//        dispatch_async(dispatch_get_main_queue(), ^{
//            
//            AppDelegate_Shared * appDelegate = (AppDelegate_Shared *)([UIApplication sharedApplication]).delegate;
//            [appDelegate.progressView setProgress:
//             (double)totalBytesSent /
//             (double)totalBytesExpectedToSend animated:YES];
//            
//        });
//    }
//}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    if (self.showProgressView) {            
        dispatch_async(dispatch_get_main_queue(), ^{                
             [progressView setHidden:YES];
        });
    }        

//    NSString *myString = [[NSString alloc] initWithData:recievedData encoding:NSUTF8StringEncoding];
//
//    NSLog(@"%@", myString);
    if(error == nil)
    {            
//        SBJSON *json = [SBJSON new];
//        NSString *responseString = [[NSString alloc] initWithData:recievedData encoding:NSUTF8StringEncoding];
//        
//        //NSLog(@"Finished (%@) %d bytes. %@", [downloadURL absoluteString], [data length], responseString);
//        
//        NSDictionary *dataSet = [json objectWithString:responseString];

        NSDictionary* dataSet = [NSJSONSerialization
                              JSONObjectWithData:recievedData
                              options:kNilOptions
                              error:&error];

        self.completion(dataSet);            
    }
    else{
      //  if (error.code == -999) {
     //       return;
     //   }
//         NSString * httpBody = [[NSString alloc] initWithData:task.currentRequest.HTTPBody encoding:NSUTF8StringEncoding];
//        
//        httpBody = [NSString stringWithFormat:@"%s\n%@", __PRETTY_FUNCTION__, httpBody];
//         [Helper MsgBox:httpBody];
        EXError * exError = [EXError errorWithDomain:error.domain code:error.code userInfo:@{NSLocalizedDescriptionKey: [NSHTTPURLResponse localizedStringForStatusCode:error.code]}];

        self.error(exError);
    //    DLog(@"Error %@", [error localizedDescription]);
    }
}

@end

1 个答案:

答案 0 :(得分:0)

原因之一可能是对HTTPS证书的检查。

Apple Documentation

  

此实例包含一个protectionSpace属性,该属性的authenticationMethod属性指示发出的质询类型(例如,对用户名和密码的请求或客户端证书)。您可以使用此值来确定是否可以应对挑战。

添加此前提条件可以检查身份验证方法并调用处理程序。

let JSONDATA = 
  {
    data: [
      {
        name: "cnt",
        level: "12"
      },
      {
        name: "stewart",
        level: "6"
      },
      {
        name: "nic",
        level: "7"
      }
    ]
  }

let { data } = JSONDATA;

data.map((obj)=>{
  console.log(obj)
})

您可以找到身份验证方法常量here