使用setSessionDidReceiveAuthenticationChallengeBlock进行AFNetworking 3.0和SSL身份验证

时间:2016-03-11 16:36:37

标签: ios ssl afnetworking-3

我尝试从AFNetworking 2.0迁移到3.0。

在之前的版本中,我将创建一个AFHTTPRequestOperation,并使用setWillSendRequestForAuthenticationChallengeBlock在另一个块中处理客户端SSL身份验证。

例如:

[operation setWillSendRequestForAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
    if ([challenge previousFailureCount] > 0) {
        //this will cause an authentication failure
        [[challenge sender] cancelAuthenticationChallenge:challenge];
        return;
    }

    //this is checking the server certificate
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {

        SecTrustResultType result;
        //This takes the serverTrust object and checkes it against your keychain
        SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);

有人能告诉我一个如何使用AFHTTPSessionManager执行此操作的示例吗?

我是否需要使用AFURLSessionManager发出请求?我确实在那里看到了一种阻止方法:

(void)setSessionDidReceiveAuthenticationChallengeBlock :(可为空的NSURLSessionAuthChallengeDisposition(^)(NSURLSession * session,NSURLAuthenticationChallenge * challenge,NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block

1 个答案:

答案 0 :(得分:1)

我正在处理同样的问题,我发现目前这个问题在AFNetworking上有一些帮助。

基本上在- (void)setTaskDidReceiveAuthenticationChallengeBlock:([long block variable type here])block;

中设置了阻止AFURLSessionManager

证书以p12格式保存。 您需要在以下两行中更改证书的文件名和密码:

NSData *p12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cert" ofType:@"p12"]];

CFStringRef password = CFSTR("YOURPASSPHRASE");

设置此块的整个代码如下所示:


    AFHTTPRequestSerializer *reqSerializer = [AFHTTPRequestSerializer serializer];
    NSMutableURLRequest *request;
    request = [reqSerializer requestWithMethod:method URLString:[actionURL absoluteString] parameters:nil error:nil];

    AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
    [securityPolicy setAllowInvalidCertificates:kAllowsInvalidSSLCertificate];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.responseSerializer = [AFHTTPResponseSerializer serializer];

    [operation setSecurityPolicy:securityPolicy];

    [operation setWillSendRequestForAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) {
        if ([challenge previousFailureCount] > 0) {
            //this will cause an authentication failure
            [[challenge sender] cancelAuthenticationChallenge:challenge];
            NSLog(@"Bad Username Or Password");
            return;
        }

        //this is checking the server certificate
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            SecTrustResultType result;
            //This takes the serverTrust object and checkes it against your keychain
            SecTrustEvaluate(challenge.protectionSpace.serverTrust, &result);

            //if we want to ignore invalid server for certificates, we just accept the server
            if (kAllowsInvalidSSLCertificate) {
                [challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge];
                return;
            } else if(result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {
                //When testing this against a trusted server I got kSecTrustResultUnspecified every time. But the other two match the description of a trusted server
                [challenge.sender useCredential:[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust] forAuthenticationChallenge: challenge];
                return;
            }
        } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
            //this handles authenticating the client certificate

            /*
             What we need to do here is get the certificate and an an identity so we can do this:
             NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:myCerts persistence:NSURLCredentialPersistencePermanent];
             [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];

             It's easy to load the certificate using the code in -installCertificate
             It's more difficult to get the identity.
             We can get it from a .p12 file, but you need a passphrase:
             */

            NSData *p12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cert" ofType:@"p12"]];

            CFStringRef password = CFSTR("YOURPASSPHRASE");
            const void *keys[] = { kSecImportExportPassphrase };
            const void *values[] = { password };
            CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
            CFArrayRef p12Items;

            OSStatus result = SecPKCS12Import((__bridge CFDataRef)p12Data, optionsDictionary, &p12Items);

            if(result == noErr) {
                CFDictionaryRef identityDict = CFArrayGetValueAtIndex(p12Items, 0);
                SecIdentityRef identityApp =(SecIdentityRef)CFDictionaryGetValue(identityDict,kSecImportItemIdentity);

                SecCertificateRef certRef;
                SecIdentityCopyCertificate(identityApp, &certRef);

                SecCertificateRef certArray[1] = { certRef };
                CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
                CFRelease(certRef);

                NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identityApp certificates:(__bridge NSArray *)myCerts persistence:NSURLCredentialPersistencePermanent];
                CFRelease(myCerts);

                [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
            } else {
                [[challenge sender] cancelAuthenticationChallenge:challenge];
            }
        } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodDefault || [[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodNTLM) {

            // For normal authentication based on username and password. This could be NTLM or Default.
            /*
             DAVCredentials *cred = _parentSession.credentials;
             NSURLCredential *credential = [NSURLCredential credentialWithUser:cred.username password:cred.password persistence:NSURLCredentialPersistenceForSession];
             [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
             */

            NSLog(@"BASIC AUTHENTICATION");

        } else {
            //If everything fails, we cancel the challenge.
            [[challenge sender] cancelAuthenticationChallenge:challenge];
        }
    }];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        NSLog(@"Success");

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        NSLog(@"Failure");

    }];

    [[NSOperationQueue mainQueue] addOperation:operation];

请参阅此链接:https://github.com/AFNetworking/AFNetworking/issues/2316#issuecomment-115181437

我现在正在尝试这个。