首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >查看自签名网站的UIWebView (没有私有api,不是NSURLConnection) -这是可能的吗?

查看自签名网站的UIWebView (没有私有api,不是NSURLConnection) -这是可能的吗?
EN

Stack Overflow用户
提问于 2012-07-20 13:03:07
回答 9查看 66.3K关注 0票数 51

有一大堆问题提出了这样的问题:我能让UIWebView查看一个自签名的HTTPS网站吗?

答案总是涉及到以下两种情况:

  1. 改为使用NSURLRequest的私有api调用:NSURLRequest NSURLConnection和委托canAuthenticateAgainstProtectionSpace etc

对我来说,这些行不通。

(1) -表示我无法成功提交到应用商店。

(2) -使用NSURLConnection意味着在接收到初始HTML页面后,必须从服务器获取的CSS、图像和其他内容不会加载。

有没有人知道如何使用UIWebView查看不涉及上述两种方法的自签名https网页?

或者-如果使用NSURLConnection实际上可以用来呈现一个包含CSS、图像和其他所有内容的网页-那就太好了!

干杯,

伸展。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2012-07-26 15:06:55

我终于明白了!

你能做的是:

照常使用UIWebView发起请求。然后-在webView:shouldStartLoadWithRequest中-我们回复NO,并使用相同的请求启动一个NSURLConnection。

使用NSURLConnection,您可以与自签名服务器通信,因为我们能够通过UIWebView不可用的额外委托方法控制身份验证。因此,使用connection:didReceiveAuthenticationChallenge,我们可以对自签名服务器进行身份验证。

然后,在connection:didReceiveData中,我们取消NSURLConnection请求,并使用UIWebView再次启动相同的请求-现在可以工作了,因为我们已经通过了服务器身份验证:)

下面是相关的代码片段。

注意:您将看到的实例变量具有以下类型:

UIWebView *_web

NSURLConnection *_urlConnection

NSURLRequest *_request

(我对_request使用了一个instance var,因为在我的例子中,它是一个包含大量登录详细信息的POST,但是如果需要的话,您可以改为使用传入的请求作为方法的参数。)

#pragma mark - Webview delegate

// Note: This method is particularly important. As the server is using a self signed certificate,
// we cannot use just UIWebView - as it doesn't allow for using self-certs. Instead, we stop the
// request in this method below, create an NSURLConnection (which can allow self-certs via the delegate methods
// which UIWebView does not have), authenticate using NSURLConnection, then use another UIWebView to complete
// the loading and viewing of the page. See connection:didReceiveAuthenticationChallenge to see how this works.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
{
    NSLog(@"Did start loading: %@ auth:%d", [[request URL] absoluteString], _authenticated);

    if (!_authenticated) {
        _authenticated = NO;

        _urlConnection = [[NSURLConnection alloc] initWithRequest:_request delegate:self];

        [_urlConnection start];

        return NO;
    }

    return YES;
}


#pragma mark - NURLConnection delegate

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
    NSLog(@"WebController Got auth challange via NSURLConnection");

    if ([challenge previousFailureCount] == 0)
    {
        _authenticated = YES;

        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

        [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];

    } else
    {
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
{
    NSLog(@"WebController received response via NSURLConnection");

    // remake a webview call now that authentication has passed ok.
    _authenticated = YES;
    [_web loadRequest:_request];

    // Cancel the URL connection otherwise we double up (webview + url connection, same url = no good!)
    [_urlConnection cancel];
}

// We use this method is to accept an untrusted site which unfortunately we need to do, as our PVM servers are self signed.
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

我希望这能帮助其他人解决我遇到的同样的问题!

票数 76
EN

Stack Overflow用户

发布于 2013-02-26 02:59:14

Stretch的答案似乎是一个很好的变通方法,但它使用的是过时的API。因此,我认为它可能值得对代码进行升级。

对于这个代码示例,我将例程添加到包含我的UIWebView的ViewController中。我把我的UIViewController做成了UIWebViewDelegate和NSURLConnectionDataDelegate。然后我添加了两个数据成员:_Authenticated和_FailedRequest。这样,代码看起来就像这样:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    BOOL result = _Authenticated;
    if (!_Authenticated) {
        _FailedRequest = request;
        [[NSURLConnection alloc] initWithRequest:request delegate:self];
    }
    return result;
}

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURL* baseURL = [_FailedRequest URL];
        if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
            NSLog(@"trusting connection to host %@", challenge.protectionSpace.host);
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        } else
            NSLog(@"Not trusting connection to host %@", challenge.protectionSpace.host);
    }
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)pResponse {
    _Authenticated = YES;
    [connection cancel];
    [_WebView loadRequest:_FailedRequest];
}

当我加载视图时,我将_Authenticated设置为NO,并且没有重置它。这似乎允许UIWebView向同一站点发出多个请求。我没有尝试切换网站,也没有试图回来。这可能会导致需要重置_Authenticated。此外,如果您要切换站点,您应该为_Authenticated保留一个字典(每个主机一个条目),而不是BOOL。

票数 65
EN

Stack Overflow用户

发布于 2014-02-12 22:28:01

这是灵丹妙药!

BOOL _Authenticated;
NSURLRequest *_FailedRequest;

#pragma UIWebViewDelegate

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request   navigationType:(UIWebViewNavigationType)navigationType {
    BOOL result = _Authenticated;
    if (!_Authenticated) {
        _FailedRequest = request;
        NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
        [urlConnection start];
    }
    return result;
}

#pragma NSURLConnectionDelegate

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURL* baseURL = [NSURL URLWithString:@"your url"];
        if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
            NSLog(@"trusting connection to host %@", challenge.protectionSpace.host);
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        } else
            NSLog(@"Not trusting connection to host %@", challenge.protectionSpace.host);
    }
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)pResponse {
_Authenticated = YES;
    [connection cancel];
    [self.webView loadRequest:_FailedRequest];
}

- (void)viewDidLoad{
   [super viewDidLoad];

    NSURL *url = [NSURL URLWithString:@"your url"];
    NSURLRequest *requestURL = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:requestURL];

// Do any additional setup after loading the view.
}
票数 17
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11573164

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档