UIWebView实现https双向认证请求

编程技术  /  houtizong 发布于 3年前   136

 

        什么是HTTPS双向认证我已在先前的博文 ASIHTTPRequest实现https双向认证请求

中有讲述,不理解的读者可以先复习一下。本文是用UIWebView来实现对需要客户端证书验证的服务请求,网上有些文章中有涉及到此内容,但都只言片语,没有讲完全,更没有完整的代码,让人困扰不已。但是此知识点其实还是比较重要并且是有一定难度的,在安全性要求比较高的场合比如银行APP中应该比较常用,当然你也可以用在你自己的项目中,为您的应用增加安全保护。

      

        废话我就少说点了,来看看关键代码吧。

 

    

@interface RootViewController : UIViewController<UIWebViewDelegate,NSURLConnectionDelegate>{    UIWebView *webView;        UIActivityIndicatorView *activityIndicatorView;        //当前的url    NSURL *_currenURL;    NSURLConnection* reUrlConnection;//重发请求    NSURLRequest* originRequest;}@property(nonatomic,assign,getter =isAuthed)BOOL authed;@property(nonatomic,strong)NSURL *currenURL;@end

 

   以上代码是UIWebView的视图控制器的声明代码,实现以下两个代理UIWebViewDelegate,NSURLConnectionDelegate

 

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{        NSString *url=[[request URL]absoluteString];        if ([url hasPrefix:@"protocol://"]) {        UIAlertView* alert=[[UIAlertView alloc]initWithTitle:@"Called by JavaScript"                                                     message:@"You've called iPhone provided control from javascript!!" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil];        [alert show];              return NO;    }        NSString* scheme = [[request URL] scheme];    NSLog(@"scheme = %@",scheme);    //判断是不是https    if ([scheme isEqualToString:@"https"]) {        //如果是https:的话,那么就用NSURLConnection来重发请求。从而在请求的过程当中吧要请求的URL做信任处理。        if (!self.isAuthed) {            originRequest = request;            NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];            [conn start];            [webView stopLoading];            return NO;        }    }    return YES;}

 以上代码重载了UIWebViewDelegate中的shouldStartLoadWithRequest 方法。

 

- (void)connection: (NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{        if ([challenge previousFailureCount]== 0) {        _authed = YES;        NSString *path = [[NSBundle mainBundle]pathForResource:@"wenfeng.xu" ofType:@"pfx"];        NSData *p12data = [NSData dataWithContentsOfFile:path];                CFDataRef inP12data = (__bridge CFDataRef)p12data;                SecIdentityRef myIdentity;        SecTrustRef myTrust;        extractIdentityAndTrust(inP12data, &myIdentity, &myTrust);        long count = SecTrustGetCertificateCount(myTrust);        NSMutableArray* myCertificates = nil;        if(count > 1) {            myCertificates = [NSMutableArray arrayWithCapacity:count];            for(int i = 1; i < count; ++i) {                [myCertificates addObject:(__bridge id)SecTrustGetCertificateAtIndex(myTrust, i)];            }        }                NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:nil persistence:NSURLCredentialPersistenceNone];                assert(credential != nil);                NSLog(@"User: %@, certificates %@ identity:%@", [credential user], [credential certificates], [credential identity]);        [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];            }else{        [challenge.sender cancelAuthenticationChallenge:challenge];    }}

 

  NSString *path = [[NSBundle mainBundle]pathForResource:@"wenfeng.xu" ofType:@"pfx"];

   以上代码声明客户端证书的类型与名称

  

OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust){    OSStatus securityError = errSecSuccess;        CFStringRef password = CFSTR("p@ssw0rd888");    const void *keys[] = { kSecImportExportPassphrase };    const void *values[] = { password };        CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);    securityError = SecPKCS12Import(inP12data, options, &items);    if (securityError == 0) {        CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);        const void *tempIdentity = NULL;        tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);        *identity = (SecIdentityRef)tempIdentity;        const void *tempTrust = NULL;        tempTrust = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);        *trust = (SecTrustRef)tempTrust;                CFIndex count = CFArrayGetCount(items);        NSLog(@"Certificates found: %ld",count);    }        if (options) {        CFRelease(options);    }        return securityError;}

  以上代码实现请求前公钥与私钥的提取

  

CFStringRef password = CFSTR("p@ssw0rd888");

 以上代码声明证书的访问密码

 

      完整的代码已在附件中,支持自签名的服务器证书,有任何问题请联系qq 359709421 如果您觉得我的文章对您有帮助,有劳参观并收藏我的网店,谢谢。  http://mrs-x.taobao.com/

 

 

 

     

上一篇:说说自信

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客