Невозможно повторно проверить подлинность с помощью других 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-адресов, которые вы вызываете.