使用NSURLSession自定义委托时不调用身份验证质询方法

时间:2014-10-09 00:20:55

标签: ios objective-c authentication nsurlsession

我正在使用通过Restful服务连接到ASP.NET Web API的iOS应用程序。我想使用自定义委托来处理身份验证质询。但委托方法并没有被调用。

http请求在视图控制器中使用以下方法编写:

- (IBAction)test:(UIButton *)sender
{
    //Get Bearer Token
    KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc]      initWithIdentifier:@"BearerToken" accessGroup:nil];
    NSString *bearerToken = [keychainItem objectForKey:(__bridge id)(kSecValueData)];

    //Configure request
    NSURL *url = [NSURL URLWithString:@"......"]; //Replace the .... with real IP Address
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];
    [request setValue:[NSString stringWithFormat:@"Bearer %@", bearerToken] forHTTPHeaderField:@"Authorization"];

    //Configure session
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

    AuthChallengeDelegate *authChallengeDel = [[AuthChallengeDelegate alloc] init];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
                                                          delegate:authChallengeDel
                                                     delegateQueue:nil];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
    [task resume];
}

在AuthChallengeDelegate类中,我实现了以下方法:

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
    NSLog(@"%@", response);   
}

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
                             NSURLCredential *credential))completionHandler
{
    NSLog(@"did receive challenge method called");
    NSLog(@"%@", challenge.protectionSpace.authenticationMethod);
}

调用第一个方法(didReceiveResponse),响应状态代码为401,其中包含" Www-Authenticate" =标题字段中的承载。但是没有调用第二种方法(didReceiveChallenge)。这里的任何人都可以告诉我为什么没有这个?

(我使用Xcode 6并在iOS8中进行模拟)

感谢。

6 个答案:

答案 0 :(得分:8)

来自iOS developer library

  

重要提示:除非服务器响应包含WWW-Authenticate标头,否则URL加载系统类不会调用其委托来处理请求质询。

我们从中了解didReceiveChallenge方法应该被称为 BUT ,只有当标题看起来像URLSession:task:didReceiveChallenge:completionHandler:

时才会调用方法'WWW-Authenticate':'Basic'

我还没有找到任何解决方案如何处理基于令牌的身份验证,其中标头为'WWW-Authenticate':'Bearer',使用身份验证质询。

答案 1 :(得分:6)

NSURLSession的代表中有两个不同的挑战/响应处理程序。您正在实施的第一个是会话级别,基本上处理服务器级别的身份验证。来自the documentation

  
      
  • 对于会话级别的挑战 - NSURLAuthenticationMethodNTLM,NSURLAuthenticationMethodNegotiate,NSURLAuthenticationMethodClientCertificate或NSURLAuthenticationMethodServerTrust - NSURLSession对象调用会话委托的URLSession:didReceiveChallenge:completionHandler:方法。如果您的应用程序未提供会话委托方法,则NSURLSession对象将调用任务委托的URLSession:task:didReceiveChallenge:completionHandler:处理质询的方法。

  •   
  • 对于非会话级别的挑战(所有其他挑战),NSURLSession对象调用会话委托的URLSession:task:didReceiveChallenge:completionHandler:处理挑战的方法。如果您的应用程序提供了会话委托,并且您需要处理身份验证,那么您必须在任务级别处理身份验证,或者提供一个显式调用每会话处理程序的任务级处理程序。 会话代理的URLSession:didReceiveChallenge:completionHandler:方法未针对非会话级别的挑战进行调用。

  •   

因此,您可能希望通过在委托对象中添加对NSURLSession 任务委托的协议支持来处理任务级别身份验证,并在任务级别提供处理程序,即 URLSession(_:task:didReceiveChallenge:completionHandler:)

答案 2 :(得分:2)

我知道此问题与iOS 8有关,但如果您使用的是iOS 9,请注意,NSAppTransportSecurity中的Info.plist密钥现在必须用于定位任何特定域名。< / p>

我遇到了完全相同的问题,并使用wireshark查看TLS网络层,以检查我所定位的图像服务器使用的TLS版本。

基于此,您可以将其添加到Info.plist,这有望解决此问题

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSExceptionDomains</key>
  <dict>
    <key>yourdomain.com</key>
    <dict>
      <key>NSIncludesSubdomains</key>
      <true/>
      <key>NSExceptionRequiresForwardSecrecy</key>
      <false/>
      <key>NSTemporaryExceptionMinimumTLSVersion</key>
      <string>TLSv1.0</string>
    </dict>
  </dict>
</dict>

答案 3 :(得分:2)

如果你写:

AuthChallengeDelegate *authChallengeDel = [[AuthChallengeDelegate alloc] init];

authChallengeDel是LOCAL,因此一旦退出方法就会释放。 所以把它变成一个属性

答案 4 :(得分:0)

在我的情况下,我认为这是重载方法,但是使用了错误的签名。

答案 5 :(得分:-1)

尝试更改委托:authChallengeDel委托:self