Str*_*tch 49 iphone uiwebview ios
有很多问题要问:我可以UIWebView查看自签名的HTTPS网站吗?
答案总是涉及:
NSURLRequest:allowsAnyHTTPSCertificateForHostNSURLConnection代替和委托canAuthenticateAgainstProtectionSpace等对我来说,这些都不行.
(1) - 表示我无法成功提交到应用商店.
(2) - 使用NSURLConnection意味着在加载初始HTML页面后必须从服务器获取的CSS,图像和其他内容.
有谁知道如何使用UIWebView查看自签名的https网页,这不涉及上述两种方法?
或者 - 如果使用NSURLConnectioncan实际上可以用来渲染一个完整的CSS,图像和其他所有的网页 - 这将是伟大的!
干杯,
拉伸.
Str*_*tch 76
终于我明白了!
你能做的是:
UIWebView正常启动您的请求.然后 - 在webView:shouldStartLoadWithRequest- 我们回复NO,而是使用相同的请求启动NSURLConnection.
使用NSURLConnection,您可以与自签名服务器通信,因为我们能够通过额外的委托方法来控制身份验证UIWebView.因此,使用connection:didReceiveAuthenticationChallenge我们可以对自签名服务器进行身份验证.
然后,在connection:didReceiveData,我们取消NSURLConnection请求,并使用UIWebView- 现在可以工作,再次启动相同的请求,因为我们已经通过服务器身份验证:)
以下是相关的代码段.
注意:您将看到的实例变量具有以下类型:
UIWebView *_web
NSURLConnection *_urlConnection
NSURLRequest *_request
(我使用实例var,_request因为在我的情况下,它是一个包含大量登录详细信息的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];
}
Run Code Online (Sandbox Code Playgroud)
我希望这能帮助其他人解决我遇到的同样问题!
Pro*_*gle 65
Stretch的答案似乎是一个很好的解决方法,但它使用了弃用的API.所以,我认为可能值得升级代码.
对于此代码示例,我将例程添加到包含我的UIWebView的ViewController.我使我的UIViewController成为一个UIWebViewDelegate和一个NSURLConnectionDataDelegate.然后我添加了2个数据成员:_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];
}
Run Code Online (Sandbox Code Playgroud)
当我加载视图并且不重置它时,我将_Authenticated设置为NO.这似乎允许UIWebView向同一站点发出多个请求.我没有尝试切换网站并试图回来.这可能导致需要重置_Authenticated.此外,如果要切换站点,则应为_Authenticated而不是BOOL保留字典(每个主机一个条目).
小智 16
这是灵丹妙药!
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.
}
Run Code Online (Sandbox Code Playgroud)
如果要访问带有自签名证书的专用服务器以进行测试,则不必编写代码.您可以手动执行系统范围的证书导入.
为此,您需要使用移动safari下载服务器证书,然后提示导入.
这可以在以下情况下使用:
如果您无权访问服务器证书,则可以回退到以下方法从任何HTTPS服务器中提取它(至少在Linux/Mac上,Windows人员必须在某处下载OpenSSL二进制文件):
echo "" | openssl s_client -connect $server:$port -prexit 2>/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' >server.pem
Run Code Online (Sandbox Code Playgroud)
请注意,根据OpenSSL版本,证书可能会在文件中加倍,因此最好使用文本编辑器查看.将文件放在网络上的某个位置或使用
python -m SimpleHTTPServer 8000
通过http:// $ your_device_ip:8000/server.pem从您的移动版Safari中访问它的快捷方式.