[より多くの情報を提供するために編集]
(私はこのプロジェクトで AFNetworking を使用していません。将来的に使用する可能性がありますが、最初にこの問題/誤解を解決したいと考えています。)
サーバーのセットアップ
ここで実際のサービスを提供することはできませんが、次のような URL に従って XML を返すシンプルで信頼性の高いサービスです。
https://username:password@example.com/webservice
GET を使用して HTTPS 経由で URL に接続し、認証の失敗 (http ステータス コード 401) を確認したいと考えています。
Web サービスが利用可能であること、および指定されたユーザー名とパスワードを使用して URL から XML を正常に取得できること (http ステータス コード 200) を確認しました。これは、Web ブラウザー、AFNetworking 2.0.3、および NSURLConnection を使用して行いました。
また、すべての段階で正しい資格情報を使用していることも確認しました。
正しい資格情報と次のコードが与えられた場合:
// 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: ...
上記のコードは機能します。サーバーに正常に接続し、http ステータス コード 200 を取得し、(XML) データを返します。
問題1
資格情報が無効な場合、この単純なアプローチは失敗します。その場合、完了ブロックは呼び出されず、ステータス コード (401) は提供されず、最終的にタスクはタイムアウトします。
試みられた解決策
NSURLSession にデリゲートを割り当て、次のコールバックを処理しています。
-(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++;
}
試行されたソリューションを使用する場合の問題 1
ivar _sessionFailureCount および _taskFailureCount の使用に注意してください。チャレンジ オブジェクトの @previousFailureCount プロパティが決して進められないため、これらを使用しています。これらのコールバック メソッドが何回呼び出されても、常にゼロのままです。
試行されたソリューションを使用する場合の問題 2
正しい資格情報を使用しているにもかかわらず (nil デリゲートでの使用が成功したことで証明されているように)、認証は失敗しています。
次のコールバックが発生します。
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")
(NSError は NSErrorFailingURLKey も提供します。これは、URL と資格情報が正しいことを示しています。)
どんな提案でも大歓迎です!