Невозможно повторно проверить подлинность с помощью других NSURLCredentials (используются старые удаленные)
Я искал stackoverflow, google, apple и другие места. Приведенные советы выглядят многообещающими, я реализовал их, но все они, похоже, не работают или не применяются.
Проблема: у меня есть NSURLConnection
со специальными учетными данными. Затем у меня есть выход из системы, где я очищаю учетные данные, защищенное пространство, я удаляю все кэшированные ответы и удаляю все файлы cookie в sharedHTTPCookieStorage
, но при повторном вызове моего аутентифицированного запроса через несколько секунд даже с неправильными учетными данными я все еще использую старый ( удаленные) учетные данные
Вот некоторые фрагменты кода, в которых удаляются учетные данные.
NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
if ([credentialsDict count] > 0) {
// the credentialsDict has NSURLProtectionSpace objs as keys and dicts of userName => NSURLCredential
NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
id urlProtectionSpace;
// iterate over all NSURLProtectionSpaces
while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator];
id userName;
// iterate over all usernames for this protectionspace, which are the keys for the actual NSURLCredentials
while (userName = [userNameEnumerator nextObject]) {
NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userName];
WriteLog(@"Method: switchView removing credential %@",[cred user]);
[[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
}
}
}
Затем я удаляю все кэшированные ответы
NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
Затем я удалю все файлы cookie
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];
for (NSHTTPCookie *cookie in cookies) {
[cookieStorage deleteCookie:cookie];
NSLog(@"deleted cookie");
}
Я также пытался использовать файлы cookie и другие политики
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0];
[request setHTTPShouldHandleCookies:NO];
if(self.currentCookies != nil){
[request setAllHTTPHeaderFields:
[NSHTTPCookie requestHeaderFieldsWithCookies:nil]];
}
theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
Я также пробовал этот намек здесь, специально сохраняя файлы cookie и передавая их снова. http://www.hanspinckaers.com/multiple-nsurlrequests-with-different-cookies. В другом блоге в Интернете предлагается добавить "#" к каждому URL-адресу, чтобы обеспечить повторную аутентификацию, которая работает, но просто не решает проблему, потому что мне нужно рассчитывать на учетные данные сеанса и возможность использовать совершенно разные учетные данные.
Является ли это ошибкой или известной проблемой, и как я могу это решить...
Прямо: что я здесь делаю неправильно?
Это действительно раздражает меня и препятствует продолжению моей работы.
Я бы очень признателен за любой вклад!
Спасибо, много!
Ответы
Ответ 1
К сожалению, похоже, что решение этой проблемы не существует.
Вы можете использовать NSURLCredentialPersistenceNone или # трюк, или вы можете определить метод делегирования connectionShouldUseCredentialStorage для возврата NO. Если вы делаете это каждый раз, и ваше приложение никогда не сохраняет учетные данные для сеанса, это заставит проблему возникать при каждом запросе.
Для приложений, которые выполняют только минимальные запросы или в конечном итоге используют cookie сеанса для аутентификации, это может работать нормально.
Для приложений, отправляющих большое количество запросов, все эти решения приводят к ответу 401 для каждого отдельного запроса и что дополнительный запрос-ответ может складываться с точки зрения данных и производительности.
Было бы неплохо, если бы вы могли сохранить хранилище учетных данных для сеанса, пока вам не нужно было выйти из системы, а затем переключиться на один из рабочих обходов, но это невозможно.
Как только вы храните учетные данные один раз для сеанса, они становятся кэшированными для всего сеанса TLS. Это приводит к необходимости ждать около 10 минут, пока этот сеанс не исчезнет.
Подробнее об этой проблеме вы можете узнать по адресу: http://developer.apple.com/library/ios/qa/qa1727/_index.html
В этом документе упоминается ограниченная работа, связанная с добавлением '.' до конца имени сервера. Однако я не смог получить эту работу.
Кроме того, это решения, о которых я могу думать:
1) Всегда используйте метод NSURLCredentialPersistenceNone и connectionShouldUseCredentialStorage, который должен генерировать 401s. Добавьте основной запрос проверки подлинности в запрос. Это должно предотвратить дополнительные 401, а также в обход хранилища учетных данных. Код для добавления этого авторизации выглядит примерно так:
NSString *s ;
NSString *authStr ;
s = [NSString stringWithFormat:@"%@:%@",user,password] ;
s = [YourBase64Encoder base64EncodingForData:[NSData dataWithBytes:[s UTF8String] length:strlen([s UTF8String])]];
authStr = [NSString stringWithFormat:@"Basic %@",s] ;
[request setValue:authStr forHTTPHeaderField:@"Authorization"] ;
Я не знаю, как это будет реализовано для других методов проверки подлинности, но я предполагаю, что это возможно.
2) Сообщите пользователю о проблеме и попросите перезапустить приложение
3) Внедрите свой собственный низкоуровневый сокет на основе механизма поиска HTTP, который полностью обходит CFNetwork. Удачи вам в этом: > )
Ответ 2
Я просто столкнулся с этой проблемой с AFNetworking. Я работаю с бэкэнд, который требует, чтобы авторизация была передана в заголовке. Однако, когда пользователь выходит из приложения и пытается войти в систему (даже с разными кредитами), я получал сообщение об ошибке с сервера. Мое решение состояло в том, чтобы очистить файлы cookie приложений, очистив authheader при выходе из системы.
- (void)clearAuthorizationHeader {
[self.manager.requestSerializer clearAuthorizationHeader];
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [storage cookies]) {
[storage deleteCookie:cookie];
}
}
Ответ 3
Я тоже столкнулся с этой проблемой. Очистка NSURLCredentialStorage
, похоже, частично работает, но кажется, что я должен ждать несколько секунд после этого, чтобы она вступила в силу. Выполнение другого HTTP-запроса без ожидающих результатов при использовании старого заголовка авторизации.
Мне удалось исправить его, передав NSURLCredentialPersistenceNone
при инициализации my NSURLCredential
:
NSURLCredential* credentials = [[NSURLCredential alloc] initWithUser:username password:password persistence:NSURLCredentialPersistenceNone];
note: это вызовет 401 Проблемы при каждом запросе HTTP, который вы сделаете с помощью этого NSURLCredential
. Однако это не проблема, если вы вернете несколько файлов cookie, которые подтверждают вашу аутентификацию.
Ответ 4
Для чего это стоит, у меня такая же проблема.
Я думаю, что это вопрос времени. При использовании симулятора, если я жду 5-10 секунд, прежде чем пытаться войти в систему, логин завершится неудачно, как ожидалось. Кроме того, когда я использую реальный телефон, я редко могу возникнуть проблема, которая может быть функцией медленного движения телефона или может быть ошибкой в симуляторе.
Ответ 5
Я знаю, что это старая тема. Однако единственное, что работает для меня, это использовать разные URL-адреса для разных сертификатов.
Он работал в моем приложении, так как у меня есть только два сертификата (один общий в ресурсах приложений и один пользовательский, загруженный из Интернета после процесса проверки пользователя). В моем случае нет файлов cookie и никаких учетных данных для очистки, поэтому ни одно из решений, которые я нашел при работе с stackoverflow, не работал.
Ответ 6
Я столкнулся с той же проблемой, теперь она работает.
Используя NSURLConnection
, эту проблему можно легко устранить, добавив случайное число в конец URL-адреса:
Итак, найдите свой URLRequest
и добавьте случайное число в URLRequest
NSInteger randomNumber = arc4random() % 999;
NSString *requestURL = [NSString stringWithFormat:@"%@?cache=%ld",yourURL,(long)randomNumber];
NSURL *URLRequest = [NSURL URLWithString:requestURL];
И убедитесь, что у вас есть случайное число в конце всех URL-адресов, которые вы вызываете.