【问题标题】:How to get IOS app to trust localhost for development API如何让 IOS 应用程序信任本地主机以进行开发 API
【发布时间】:2019-10-27 08:19:09
【问题描述】:

使用 Visual Studio for Mac,我创建了一个 RESFUL API(从 API 项目模板开发),它开箱即用地输出一个非常简单的 JSON 文件(即 ["value1","value2"]),如下所示网址:https://localhost:5001/api/values

所以,在后台在 Visual Studio 上运行 API 的同时,我也在同一台计算机上运行 XCode;因为我正在开发一个需要连接到 API url 并输出预期 JSON 响应的应用程序。

问题是由于信任错误而不断失败:“TIC SSL 信任错误...NSURLSession/NSURLConnection HTTP 加载失败”。

根据我的研究,我认为我需要将 localhost 的自签名证书安装到我的 XCode 模拟器上,以便它允许应用程序信任该 url。如何访问此 localhost 证书?

或者这甚至是正确的方法吗?

产生信任错误的代码:

// Specify the base url...
static NSString *const API_URL = @"https://localhost:5001";
// Specify completed url ...
NSString *urlAppend = [NSString stringWithFormat:@"/api/values"];
NSString *urlStr = [[[NSString alloc] initWithString:API_URL]
stringByAppendingString:urlAppend];        

// Specify the URL object that can return JSON, XML, etc....
NSURL *url = [[NSURL alloc] initWithString:urlStr];

// Create an NSURLSessionDataTask that does the GET request at the specified URL (using NSURLSession shared session)...
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
              dataTaskWithURL:url
              completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                  // Handle response (output respnose to log window))...
                  NSLog(@"%@", [output initWithData:data  encoding:(NSASCIIStringEncoding)] ? : @"no data");
              }];

// Start task ....
[task resume];

【问题讨论】:

    标签: objective-c ssl localhost trust self-signed-certificate


    【解决方案1】:

    解决此问题的最佳方法是使用Perform Manual Server Trust Authentication 获取本地开发服务器的 url(在后台运行)。这是通过使用NSURLSessionDelegateURLSession:didReceiveChallenge:completionHandler: 委托方法来完成的;这将使您有机会匹配 localhost url 并在会话数据任务开始时手动信任它(在它由于不受信任的自签名证书而拒绝之前)。

    方法如下:

    第一步:将 NSURLSession 操作封装在一个类中,比如“Networking”,它实现了 NSURLSessionDelegate 协议;并添加手动信任您的 localhost url(指定为“DEV_URL”)的委托方法。

    // Networking.h
    #import <Foundation/Foundation.h>
    
    @interface Networking : NSObject <NSURLSessionDelegate>
    - (void) fetchContentsOfUrl:(NSURL *)url
                     completion:(void (^)(NSData *data, NSError *error)) completionHandler;
    @end
    
    // Networking.m
    #import "Networking.h"
    
    static NSString *const DEV_URL = @"https://localhost:5001";
    @implementation Networking
    - (void) fetchContentsOfUrl:(NSURL *)url
                     completion:(void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler {
        NSURLSession *dataSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
    
        NSURLSessionDataTask *dataTask = [dataSession
                                          dataTaskWithURL:url
                                          completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    
                                              if (completionHandler == nil) {
                                                  return;
                                              }
    
                                              if (error){
                                                  completionHandler(nil, error);
                                                  return;
                                              }
    
                                              completionHandler(data, nil);
                                          }];
    
        [dataTask resume];
    }
    
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
    
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            NSURL* baseURL = [NSURL URLWithString:DEV_URL];
            if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
                NSLog(@"trusting connection to host %@", challenge.protectionSpace.host);
                completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
            } else {
                NSLog(@"Not trusting connection to host %@", challenge.protectionSpace.host);
                completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
            }
        }
        [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
    }
    @end
    

    第 2 步:将您的原始代码替换为 Networking 类的实例化并调用 fetchContentsOfUrl:completion: 方法,该方法调用 NSURLSessionDataTask,如下所示:

        Networking *networker = [[Networking alloc] init];
        [networker fetchContentsOfUrl:url completion:^(NSData *data, NSError *error) {        
            if (error == nil) {
                NSString *output = [NSString alloc];
                NSLog(@"%@", [output initWithData:data  encoding:(NSASCIIStringEncoding)] ? : @"no data");
            }
        }];
    

    一切准备就绪!

    【讨论】:

      【解决方案2】:

      您可以试试这个:在每个发出 HTTP 请求的 ViewController 的顶部,就在导入部分的下方,添加以下代码:

      @interface NSURLRequest (DummyInterface)
      + (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
      + (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
      @end
      

      然后,在你提出请求的地方,调用这个:

      [request setHTTPBody:data];
      
      [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
      
      NSError *error;
      NSHTTPURLResponse  *response = nil;
      
      NSData *data2 = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-07
        • 2011-02-13
        • 2011-08-28
        • 1970-01-01
        • 1970-01-01
        • 2011-07-06
        • 1970-01-01
        • 2014-02-05
        相关资源
        最近更新 更多