NSURLSessionTask身份验证质询完成处理器和NSURLAuthenticationChallenge客户端 [英] NSURLSessionTask authentication challenge completionHandler and NSURLAuthenticationChallenge client
问题描述
我正在实现自定义NSURLProtocol
,并且内部希望将NSURLSession
与数据任务一起用于内部联网,而不是NSURLConnection
.
I am implementing a custom NSURLProtocol
, and internally want to use NSURLSession
with data tasks for internal networking instead of NSURLConnection
.
我遇到了一个有趣的问题,想知道NSURLSession
/NSURLSessionTask
的质询处理程序的内部实现.
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;
这里我基本上提供了两个不同的质询处理程序,一个是completionHandler
块,该处理程序提供了处理质询的所有必要信息,但是还有一个遗留的NSURLAuthenticationChallenge.client
,其方法非常对应使用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.
由于我正在开发协议,并且想将某些身份验证挑战传递给URL加载系统以供调用API实施,因此我需要使用NSURLSession
客户端方法:
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;
我的问题是completionHandler
和NSURLAuthenticationChallenge.client
的内部实现是否相同,如果可以,我是否可以跳过委托方法中的完成处理程序,以期望URL加载系统将调用适当的方法? NSURLAuthenticationChallenge.client
方法?
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?
推荐答案
要回答我自己的问题,答案是否定的.此外,Apple提供的质询发送者未实现完整的NSURLAuthenticationChallengeSender
协议,因此当客户端尝试响应质询时会崩溃:
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];
这篇关于NSURLSessionTask身份验证质询完成处理器和NSURLAuthenticationChallenge客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!