iOS / Cocoa - NSURLSession - Gestion de l'autorisation HTTPS de base
[édité pour fournir plus d'informations]
(Je ne suis pas en utilisant AFNetworking pour ce projet. Je peut le faire à l'avenir, mais pour résoudre ce problème/incompréhension de la première.)
DE CONFIGURATION DU SERVEUR D'
Je ne peux pas en mesure de fournir les services proposés ici, mais c'est un simple service fiable et qui renvoie XML selon une URL de la forme:
https://username:[email protected]/webservice
Je veux me connecter à l'URL en HTTPS à l'aide de GET, et à déterminer les échecs d'authentification (code d'état http 401).
J'ai confirmé que le service web est disponible, et que je peux avec succès (avec un code d'état http 200) saisir XML à partir de l'url spécifié à l'aide d'un nom d'utilisateur et mot de passe. Je l'ai fait avec un navigateur web, et avec AFNetworking 2.0.3, et en utilisant NSURLConnection.
J'ai également confirmé que je suis en utilisant les informations d'identification correctes à toutes les étapes.
Donné les bonnes informations d'identification et le code suivant:
//Note: NO delegate provided here.
self.sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfig
delegate:nil
delegateQueue:nil];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:self.requestURL completionHandler: ...
Le code ci-dessus va travailler. Il va réussir à se connecter au serveur, obtenir un code d'état http 200, et de renvoyer les données (XML).
PROBLÈME 1
Cette simple approche échoue dans les cas où les informations ne sont pas valides. Dans ce cas, l'achèvement de bloc n'est jamais appelé, pas de code d'état (401) est fourni, et finalement, le temps de travail.
TENTATIVE DE SOLUTION
J'ai affecté un délégué à la NSURLSession, et je suis de la manipulation de l'rappels suivants:
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (_sessionFailureCount == 0) {
NSURLCredential *cred = [NSURLCredential credentialWithUser:self.userName password:self.password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
_sessionFailureCount++;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (_taskFailureCount == 0) {
NSURLCredential *cred = [NSURLCredential credentialWithUser:self.userName password:self.password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
_taskFailureCount++;
}
PROBLÈME 1 LORS DE L'UTILISATION DE LA TENTATIVE DE SOLUTION
Veuillez noter que l'utilisation de ivars _sessionFailureCount et _taskFailureCount. Je suis à l'aide de ces car le défi de l'objet @previousFailureCount propriété n'est jamais avancé! Elle reste toujours à zéro, peu importe combien de fois ces méthodes de rappel sont appelés.
PROBLÈME 2 LORS DE L'UTILISATION DE LA TENTATIVE DE SOLUTION
En dépit de l'utilisation des informations d'identification correctes (comme le prouve la réussite de leur utilisation avec un nul de son délégué), l'authentification échoue.
Les rappels suivants se produisent:
URLSession:didReceiveChallenge:completionHandler:
(challenge @ previousFailureCount reports as zero)
(_sessionFailureCount reports as zero)
(completion handler is called with correct credentials)
(there is no challenge @error provided)
(there is no challenge @failureResponse provided)
URLSession:didReceiveChallenge:completionHandler:
(challenge @ previousFailureCount reports as **zero**!!)
(_sessionFailureCount reports as one)
(completion handler is called with request to cancel challenge)
(there is no challenge @error provided)
(there is no challenge @failureResponse provided)
//Finally, the Data Task's completion handler is then called on us.
(the http status code is reported as zero)
(the NSError is reported as NSURLErrorDomain Code=-999 "cancelled")
(Le NSError fournit également un NSErrorFailingURLKey, qui me montre que l'URL et les informations d'identification sont correctes.)
Toutes les suggestions sont les bienvenues!
source d'informationauteur Womble
Vous devez vous connecter pour publier un commentaire.
Vous n'avez pas besoin de mettre en œuvre un délégué méthode pour cela, il suffit de définir l'autorisation d'en-tête HTTP à la demande, par exemple,
Invité vs Non l'Authentification HTTP
Il me semble que toute la documentation sur NSURLSession et l'Authentification HTTP saute sur le fait que l'exigence de l'authentification peut être invité (comme c'est le cas lors de l'utilisation d'un .htpassword fichier) ou spontanées (comme c'est habituellement le cas lorsque l'on traite avec un service REST).
Pour l'invité cas, la bonne stratégie est de mettre en œuvre la méthode du délégué:
URLSession:task:didReceiveChallenge:completionHandler:
; pour le spontanées cas, la mise en œuvre de la méthode du délégué ne vous offrons la possibilité de vérifier le SSL défi (par exemple, la protection de l'espace). Par conséquent, lorsque vous traitez avec le RESTE, vous aurez probablement besoin d'ajouter des en-têtes d'Authentification manuellement comme @malhal souligné.Plus en détail, voici une solution qui évite la création d'un NSURLRequest.
J'espère que cela va aider quelqu'un qui s'exécute dans ce mal documenté différence. J'ai enfin compris à l'aide de code de test, un proxy local ProxyApp et la force de la désactivation de
NSAppTransportSecurity
dans mon projet deInfo.plist
fichier (nécessaire pour l'inspection du trafic SSL via un proxy sur iOS 9/OS x 10.11).Réponse courte: Le comportement que vous décrivez est compatible avec un serveur de base d'échec de l'authentification. Je sais que vous avez signalé que vous avez vérifié que c'est correct, mais je soupçonne que certains fondamentaux problème de validation sur le serveur (pas votre iOS code).
Réponse longue:
Si vous utilisez
NSURLSession
sans le délégué et inclure le nom d'utilisateur/mot de passe dans l'URL, puiscompletionHandler
bloc de laNSURLSessionDataTask
sera appelée si le nom d'utilisateur/mot de passe est correct. Mais, si l'authentification échoue,NSURLSession
apparaît à plusieurs reprises tenter de faire la demande, en utilisant les mêmes informations d'authentification de tous les temps, et lecompletionHandler
ne semble pas appelée. (J'ai remarqué qu'en regardant la connexion avec Charles Proxy).Cela ne me frappe pas très prudent de
NSURLSession
mais de nouveau, les délégué-moins le rendu ne peut pas vraiment faire beaucoup plus que cela. Lors de l'utilisation de l'authentification, à l'aide de ladelegate
-fondé de l'approche semble plus robuste.Si vous utilisez le
NSURLSession
avec ledelegate
spécifié (et pascompletionHandler
paramètre lorsque vous créez la tâche de données), vous pouvez examiner la nature de l'erreur dansdidReceiveChallenge
à savoir examiner leschallenge.error
et lachallenge.failureResponse
objets. Vous pourriez vouloir mettre à jour votre question, avec ces résultats.Que d'un côté, vous avez l'air d'être le maintien de votre propre
_failureCount
compteur, mais vous pouvez probablement vous en prévaloirchallenge.previousFailureCount
de la propriété, à la place.Vous pouvez peut-être partager quelques détails sur la nature de l'authentification de votre serveur à l'aide. Je ne demander, parce que quand je sécuriser un répertoire sur mon serveur web, il n'appelle pas la
NSURLSessionDelegate
méthode:Mais plutôt, il appelle la
NSURLSessionTaskDelegate
méthode:Comme je l'ai dit, le comportement que vous décrivez est consistent avec un échec d'authentification sur le serveur. Partager les détails au sujet de la nature de la configuration de l'authentification sur votre serveur et les détails de la
NSURLAuthenticationChallenge
objet peut nous aider à diagnostiquer ce qui se passe. Vous pouvez également taper l'URL avec le nom d'utilisateur/mot de passe dans un navigateur web et qui peut aussi confirmer si il ya un problème d'authentification.