我在Objective-C方面还比较新手,但我正在开发一个应用程序,其中包含一个UIWebView,加载一些Web内容。所有的网页都需要客户端证书进行身份验证,我已经为此苦恼了几天。
有人知道如何在UIWebView中实现它的流程吗?
谢谢!
我在Objective-C方面还比较新手,但我正在开发一个应用程序,其中包含一个UIWebView,加载一些Web内容。所有的网页都需要客户端证书进行身份验证,我已经为此苦恼了几天。
有人知道如何在UIWebView中实现它的流程吗?
谢谢!
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
接下来,UIWebView将能够毫无问题地加载所有内容。
如果你刚开始学习Objective-C,我想你也是Foundation框架的新手,所以这里提供一点帮助。
为了解决这个问题,我使用了ASIHTTPRequest,因为它已经嵌入到我们的项目中。但是你也可以使用NSURLConnection,并在NSURLConnectionDelegate方法中实现逻辑:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
因此,这是我提供一个客户端证书给ASIHTTPRequest以前向UIWebView请求的代码:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"test.cert" ofType:@"pfx"]];
[self extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];
NSURL *serverUrl = [NSURL URLWithString:URL_SECURE_SERVER];
ASIHTTPRequest *firstRequest = [ASIHTTPRequest requestWithURL:serverUrl];
[firstRequest setValidatesSecureCertificate:NO];
[firstRequest setClientCertificateIdentity:identity];
[firstRequest startSynchronous];
return YES;
}
我正在同步发送请求,以确保在让UIWebView开始加载之前完成请求。
我使用了一种方法从证书中检索身份,该方法是:
- (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data
{
OSStatus securityError = errSecSuccess;
NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"mobigate" forKey:(id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
*outTrust = (SecTrustRef)tempTrust;
}
else {
NSLog(@"Failed with error code %d",(int)securityError);
return NO;
}
return YES;
}
这里使用 NSURLConnection 而不是 ASIHTTPRequest 来实现同样的技术。
要使用 NSURLConnection 进行证书验证,您需要实现 NSURLConnectionDelegate 方法:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
+ (NSURLCredential *)credentialWithIdentity:(SecIdentityRef)identity certificates:(NSArray *)certArray persistence:(NSURLCredentialPersistence)persistence
{
NSString *certPath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath];
SecIdentityRef myIdentity; // ???
SecCertificateRef myCert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
[certData release];
SecCertificateRef certArray[1] = { myCert };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
CFRelease(myCert);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity
certificates:(NSArray *)myCerts
persistence:NSURLCredentialPersistencePermanent];
CFRelease(myCerts);
}
- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
在 [挑战发送者] 上
你应该拥有所需的一切。祝你好运。
[[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"]
将返回 nil
,并且所有后续使用 certPart
/certData
的调用都将失败。 - kervich