【问题标题】:Request to web service over SSL通过 SSL 请求 Web 服务
【发布时间】:2013-02-15 09:51:29
【问题描述】:

我正在努力使用 https 请求 Web 服务。我收到这种错误:

An error occured : The certificate for this server is invalid. You might be connecting to a server that is pretending to be “SERVER_ADDRESS” which could put your confidential information at risk.

我没有使用 NSUrlConnectionDelegate。这是我的方法:

- (void)sendRequestWithUrl:(NSURL*)url block:(void (^)(NSDictionary *dict, NSError *error)) block{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    NSError* err = nil;
    NSHTTPURLResponse* rsp = nil;
    // Perform the request synchronously on this thread
    NSData *rspData = [NSURLConnection sendSynchronousRequest:request returningResponse:&rsp error:&err];
    if (rspData && err == nil) {
        NSDictionary *result = [NSJSONSerialization JSONObjectWithData:rspData options:NSJSONReadingMutableLeaves error:&err];
        if(result) {
            block(result, err);
        } else {
            block(nil, err);
        }
    }else{
        DLog(@"Requesting URL: %@  An error occured : %@",url,[err localizedDescription]);
        block(nil, err);
    }
}

我该如何解决这个问题?

【问题讨论】:

标签: ios objective-c ios6 nsmutableurlrequest


【解决方案1】:

Apple 有一个技术说明很好地涵盖了这一点:

《技术说明 TN2232:HTTPS 服务器信任评估》

https://developer.apple.com/library/ios/#technotes/tn2232/_index.html

【讨论】:

    【解决方案2】:

    我的解决方案是创建类AsyncURLConnection 这个代码我在http://stackoverflow.com 某处找到但现在找不到。所以我会给出代码:

    AsyncURLConnection:

    .h

    #import <Foundation/Foundation.h>
    
    typedef void (^completeBlock_t)(NSData *data);
    typedef void (^errorBlock_t)(NSError *error);
    
    @interface AsyncURLConnection : NSObject{
        NSMutableData *data_;
        completeBlock_t completeBlock_;
        errorBlock_t errorBlock_;
    }
    
    + (id)request:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
    - (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
    + (id)requestWithMutable:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
    - (id)initWithMutableRequest:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock;
    @end
    

    .m

    #import "AsyncURLConnection.h"
    
    @implementation AsyncURLConnection
    
    + (id)requestWithMutable:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
    {
        return [[self alloc] initWithMutableRequest:request completeBlock:completeBlock errorBlock:errorBlock];
    }
    
    + (id)request:(NSString*)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
    {
        return [[self alloc] initWithRequest:requestUrl
                                completeBlock:completeBlock errorBlock:errorBlock];
    }
    
    - (id)initWithRequest:(NSString *)requestUrl completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
    {
        if ((self=[super init])) {
            data_ = [[NSMutableData alloc] init];
            completeBlock_ = [completeBlock copy];
            errorBlock_ = [errorBlock copy];
            NSURL *url = [NSURL URLWithString:requestUrl];
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            [NSURLConnection connectionWithRequest:request delegate:self];
        }
        return self;
    }
    
    - (id)initWithMutableRequest:(NSMutableURLRequest *)request completeBlock:(completeBlock_t)completeBlock errorBlock:(errorBlock_t)errorBlock
    {
        if ((self=[super init])) {
            data_ = [[NSMutableData alloc] init];
            completeBlock_ = [completeBlock copy];
            errorBlock_ = [errorBlock copy];
            [NSURLConnection connectionWithRequest:request delegate:self];
        }
        return self;
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        [data_ setLength:0];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        [data_ appendData:data];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        completeBlock_(data_);
    }
    
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        errorBlock_(error);
    }
    
    
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
        if ([challenge previousFailureCount] == 0)
        {
            NSURLCredential *newCredential;
            newCredential=[NSURLCredential credentialWithUser:@"someUser"
                                                     password:@"someUser"
                                                  persistence:NSURLCredentialPersistenceForSession];
            [[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
            DLog(@"responded to authentication challenge");
    
        }else{
            DLog(@"previous authentication failure");
        }
    }
    

    所以在某些控制器中可以使用这个类:

    + (void) downloadFileForURL:(NSURL *) url completionBlock:(void (^)(NSData *data, NSError *error)) block {
        NSString *requestURL = @"https://www.google.lt/restServer/Method";
        [AsyncURLConnection request:requestURL completeBlock:^(NSData *data) {
            /* success! */
            dispatch_queue_t downloadQueue = dispatch_queue_create("Download queue", NULL);
            dispatch_async(downloadQueue, ^{
                /* process downloaded data in Concurrent Queue */
                if (data != nil) {
                    block(data, nil);
                }else{
                    block(nil,nil);
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    /* update UI on Main Thread */
                });
            });
        } errorBlock:^(NSError *error) {
            /* error! */
            block(nil,error);
        }];
    }
    

    希望这段代码能帮到一些人。

    谢谢大家的回答。

    【讨论】:

      【解决方案3】:

      您应该将以下委托方法添加到您的通信类。

      - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
      {
          if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
          {
              if ([YOUR_HOST isEqualToString:challenge.protectionSpace.host])
              {
                  [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];           
              }
          }   
          [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
      }
      
      - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
      {
          return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
      }
      

      【讨论】:

        【解决方案4】:

        自签名证书总是会发生这种情况。通过使用NSURLConnectionDelegate

        - (BOOL)connection:(NSURLConnection *)connection
        canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
        {
            if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
                return YES;
            }
        }
        

        【讨论】:

        • 如何调整此代码以供我使用?我知道如何用 NSURLConnectionDelegate 来做,但是如何用块来做
        • 为什么你不想使用 NSURLConnectionDelegate?有什么东西可以破坏你的代码吗?
        • 我想更新我当前的代码,因为在其他方面我需要做很多改变,因为现在一切都在块中完成。我也喜欢用这种方法编写代码
        • 看看 AFNetworking。它使用成功和失败块以及 NSURLConnectionDelegate。如果您不能直接使用该框架,您可能会在那里找到可以帮助您解决问题的代码。
        【解决方案5】:

        尝试这个委托方法为我解决了同样的问题。

        - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
            return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
        }
        
        - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
            [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-04-25
          • 1970-01-01
          • 1970-01-01
          • 2016-11-09
          • 2012-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多