El método de desafío de authentication no se llama cuando se utiliza el delegado personalizado NSURLSession

Estoy trabajando en una aplicación iOS que se conecta a una API web ASP.NET a través de services Restful. Quiero usar un delegado personalizado para manejar el desafío de authentication. Pero el método de delegado no se llama.

La request http se escribe en el siguiente método dentro de un controller de vista:

- (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]; } 

En la class AuthChallengeDelegate, he implementado el siguiente método:

 - (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, NSURLCnetworkingential *cnetworkingential))completionHandler { NSLog(@"did receive challenge method called"); NSLog(@"%@", challenge.protectionSpace.authenticationMethod); } 

Se llama al primer método (didReceiveResponse) y el código de estado de respuesta es 401 con "Www-Authenticate" = Portador en el campo de encabezado. Pero el segundo método (didReceiveChallenge) no se llama. ¿Alguien aquí puede darme una idea de por qué no se llama?

(Estoy usando Xcode 6 y simulando en iOS8)

Gracias.

Desde la biblioteca de desarrolladores de iOS

Importante: las classs del sistema de carga de URL no llaman a sus delegates para manejar los desafíos de la request a less que la respuesta del server contenga un encabezado de authentication de WWW.

Desde donde entendemos que los methods didReceiveChallenge deberían llamarse PERO el método URLSession:task:didReceiveChallenge:completionHandler: se llama solo cuando el encabezado se ve como 'WWW-Authenticate':'Basic'

No encontré ninguna solución de cómo manejar la authentication basada en token donde el encabezado es 'WWW-Authenticate':'Bearer' como en la pregunta usando los desafíos de authentication.

Hay dos manipuladores de desafío / respuesta diferentes en los delegates de NSURLSession. El primero, que está implementando, está en el nivel de session y, básicamente, maneja la authentication a nivel de server. De la documentation :

  • Para los desafíos de nivel de session: NSURLAuthenticationMethodNTLM, NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate o NSURLAuthenticationMethodServerTrust: el object NSURLSession llama a la URLSession del delegado de session: didReceiveChallenge: completionHandler: method. Si su aplicación no proporciona un método de delegado de session, el object NSURLSession llama a la tarea URLSession del delegado de tarea: didReceiveChallenge: completionHandler: método para manejar el desafío.

  • Para los desafíos que no son de session (todos los demás), el object NSURLSession llama a la session URLSession: task del delegado de session: didReceiveChallenge: completionHandler: método para manejar el desafío. Si su aplicación proporciona un delegado de session y necesita manejar la authentication, debe manejar la authentication en el nivel de tarea o proporcionar un controller de nivel de tarea que llame explícitamente al controller por session. La session URLSession del delegado de session: didReceiveChallenge: completionHandler: no se llama al método para desafíos que no son de session.

Por lo tanto, probablemente quiera manejar la authentication a nivel de tarea agregando soporte de protocolo para NSURLSession Task Delegate en su object de delegado y proporcionando un controller en el nivel de tarea, es decir, URLSession(_:task:didReceiveChallenge:completionHandler:) .

Sé que este problema está relacionado con iOS 8, pero si usa iOS 9, recuerde que la key NSAppTransportSecurity en su Info.plist ahora es obligatoria para apuntar a cualquier nombre de dominio específico.

Tenía exactamente el mismo problema y usé wireshark para mirar la capa de networking de TLS para verificar qué versión de TLS utilizaba el server de imágenes al que estaba apuntando.

Sobre la base de eso, puede agregar esto a su Info.plist y que, con suerte, puede resolver este problema

 <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> 

si escribes:

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

authChallengeDel es LOCAL por lo que se lanzará tan pronto como salga de los methods. Entonces conviértalo en una propiedad

Intente cambiar de delegado: authChallengeDel para delegar: self