NSURLSessionTask authentication challenge completionHandler and NSURLAuthenticationChallenge client

感情迁移 提交于 2019-12-06 06:08:48

问题


I am implementing a custom NSURLProtocol, and internally want to use NSURLSession with data tasks for internal networking instead of NSURLConnection.

I have hit an interesting problem and wonder about the internal implementation of the challenge handler of NSURLSession/NSURLSessionTask.

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                            didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
                              completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;

Here I am basically provided with two different challenge handlers, one being the completionHandler block, which is provided with all necessary information to handle the challenge, but there is also the legacy NSURLAuthenticationChallenge.client which has methods that correspond pretty much one to one with the completionHandler information options.

Since I am developing a protocol, and would like to pass certain authentication challenges upward the URL loading system for the calling API to implement, I need to use the NSURLSession client method:

- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

My question is whether the internal implementation of the completionHandler and NSURLAuthenticationChallenge.client is the same, and if so, can I skip calling the completion handler in the delegate method, with expectance that the URL loading system will call the appropriate NSURLAuthenticationChallenge.client method?


回答1:


To answer my own question, the answer is no. Moreover, Apple's provided challenge sender does not implement the entire NSURLAuthenticationChallengeSender protocol, thus crashing when client attempts to respond to challenge:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFURLSessionConnection performDefaultHandlingForAuthenticationChallenge:]: unrecognized selector sent to instance 0x7ff06d958410'

My solution was to create a wrapper:

@interface CPURLSessionChallengeSender : NSObject <NSURLAuthenticationChallengeSender>

- (instancetype)initWithSessionCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;

@end

@implementation CPURLSessionChallengeSender
{
    void (^_sessionCompletionHandler)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential);
}

- (instancetype)initWithSessionCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    self = [super init];

    if(self)
    {
        _sessionCompletionHandler = [completionHandler copy];
    }

    return self;
}

- (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    _sessionCompletionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}

- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    _sessionCompletionHandler(NSURLSessionAuthChallengeUseCredential, nil);
}

- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
{
    _sessionCompletionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}

- (void)performDefaultHandlingForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    _sessionCompletionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}

- (void)rejectProtectionSpaceAndContinueWithChallenge:(NSURLAuthenticationChallenge *)challenge
{
    _sessionCompletionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
}

@end

And I replace the challenge object with a new one, using my wrapped sender:

NSURLAuthenticationChallenge* challengeWrapper = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:challenge sender:[[CPURLSessionChallengeSender alloc] initWithSessionCompletionHandler:completionHandler]];
[self.client URLProtocol:self didReceiveAuthenticationChallenge:challengeWrapper];


来源:https://stackoverflow.com/questions/27604052/nsurlsessiontask-authentication-challenge-completionhandler-and-nsurlauthenticat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!