Не удается выполнить повторную аутентификацию с использованием разных учетных данных NSURLC (используются старые удаленные)

я искал 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-other-cookies. В Интернете есть еще один блог, предлагающий добавить «#» к каждому URL-адресу, чтобы обеспечить повторную аутентификацию, которая работает, но просто не решает проблему, потому что мне нужно рассчитывать на учетные данные сеанса и возможность использовать совершенно другие учетные данные.

Является ли это ошибкой или известной проблемой, и как мне действительно решить эту проблему... Скажем прямо: что я здесь делаю неправильно?

Это меня очень беспокоит и мешает мне продолжать свою работу.

Буду очень признателен за любой вклад!

Большое спасибо!


person Mike F    schedule 19.09.2011    source источник
comment
У меня та же проблема — я не могу получить учетные данные из хранилища после того, как вставил их. Вызов -removeCredential..., похоже, не дает никакого эффекта.   -  person paulmelnikow    schedule 11.09.2012
comment
И, что бы это ни стоило, мое исправление состояло в том, чтобы адаптировать мое приложение для использования асинхронного API, что позволяет мне предоставлять учетные данные именно так, как я выбираю.   -  person paulmelnikow    schedule 11.09.2012
comment
Если вы считаете, что удаление файлов cookie и очистка кеша могут не сработать, тогда другим способом будет зашифровать учетные данные, идентификатор пользователя и/или пароль случайным текстом, чтобы вход не выполнялся до тех пор, пока не будут введены правильные учетные данные!   -  person AnBisw    schedule 18.09.2012
comment
@Annjawn: тебе это подходит? У меня не было никакого успеха, шифрующего учетные данные. Как описано в моем посте, работает скремблирование URL-адреса с # или случайным числом, однако это больше похоже на взлом, чем на решение.   -  person Mike F    schedule 01.10.2012


Ответы (6)


К сожалению, похоже, решения этой проблемы не существует.

Вы можете использовать NSURLCredentialPersistenceNone или трюк #, или вы можете определить метод делегата connectionShouldUseCredentialStorage для возврата NO. Если вы делаете это каждый раз, и ваше приложение никогда не сохраняет учетные данные для сеанса, это заставит вызов возникать при каждом запросе.

Для приложений, которые выполняют только минимальные запросы или в конечном итоге используют файл cookie сеанса для аутентификации, это может работать нормально.

Для приложений, которые отправляют большое количество запросов, все эти решения приводят к ответу 401 на каждый отдельный запрос, и этот дополнительный запрос-ответ может складываться с точки зрения данных и производительности.

Было бы неплохо, если бы вы могли сохранять хранилище учетных данных для сеанса до тех пор, пока вам не потребуется выйти из системы, а затем переключиться на один из обходных путей, но это невозможно.

Как только вы сохраняете учетные данные один раз для сеанса, они кэшируются для всего сеанса TLS. Это приводит к необходимости ждать около 10 минут, пока этот сеанс не исчезнет.

Подробнее об этой проблеме можно прочитать по адресу: http://developer.apple.com/library/ios/qa/qa1727/_index.html

В этом документе упоминается ограниченный обходной путь, который включает добавление '.' до конца имени сервера. Однако мне не удалось заставить это работать.

Кроме этого, вот решения, о которых я могу думать:

1) Всегда используйте обходной путь NSURLCredentialPersistenceNone и connectionShouldUseCredentialStorage, который должен генерировать ошибки 401. Добавьте заголовок базовой аутентификации в запрос самостоятельно. Это должно предотвратить дополнительные ошибки 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. Удачи в этом :>)

person Rich Waters    schedule 18.08.2013
comment
В итоге я добавил поле заголовка Authorization ко всем своим запросам, как вы и предложили. Не удалось найти другого способа избежать проблемы, с которой я столкнулся, когда можно было войти в систему с неправильными учетными данными сразу после выхода из системы. - person einarnot; 27.01.2016

Я только что столкнулся с этой проблемой с AFNetworking. Я работаю с серверной частью, которая требует авторизации в заголовке. Однако, когда пользователь выходит из приложения и пытается снова войти в систему (даже с разными учетными данными), я получаю сообщение об ошибке с сервера. Мое решение состояло в том, чтобы очистить файлы cookie моих приложений при очистке заголовка авторизации при выходе из системы.

- (void)clearAuthorizationHeader {
    [self.manager.requestSerializer clearAuthorizationHeader];
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *cookie in [storage cookies]) {
        [storage deleteCookie:cookie];
    }
}
person Segsfault    schedule 13.01.2015
comment
вы только что спасли мой день - у меня была точно такая же проблема с соединением oauth, в отличие от базового, и учетные данные использовались повторно. очистка файлов cookie при выходе из системы помогла (в дополнение к удалению учетных данных и т. д.) - person adam.wulf; 27.05.2015

Я тоже столкнулся с этой проблемой. Очистка NSURLCredentialStorage, похоже, частично работает, но мне кажется, что после этого мне нужно подождать несколько секунд, чтобы она вступила в силу. Выполнение другого HTTP-запроса без ожидания приводит к использованию старого заголовка авторизации.

Я смог исправить это, передав NSURLCredentialPersistenceNone при инициализации моего NSURLCredential:

NSURLCredential* credentials = [[NSURLCredential alloc] initWithUser:username password:password persistence:NSURLCredentialPersistenceNone];

примечание: это вызовет 401 вызов при каждом HTTP-запросе, который вы делаете с помощью этого NSURLCredential. Однако это не проблема, если вы возвращаете некоторые файлы cookie, которые обеспечивают вашу аутентификацию.

person JasonZ    schedule 10.07.2012

Для чего это стоит, у меня та же проблема.

Я думаю, что это проблема времени. При использовании симулятора, если я подожду 5-10 секунд, прежде чем снова попытаюсь войти в систему, произойдет сбой входа в систему, как и ожидалось. Кроме того, когда я использую реальный телефон, у меня редко возникает проблема, которая может быть связана с более медленным телефоном или может быть ошибкой в ​​​​симуляторе.

person Vic    schedule 06.10.2011
comment
Хорошо, это звучит интересно - я также думаю, что это как-то связано со временем, но только в незначительной степени. Я не получаю такого же поведения, как вы. Я не имел дело с этой ошибкой в ​​​​течение некоторого времени - я бесстыдно перезапускаю свое приложение при выходе из системы: / - в любом случае в моем случае у меня все еще есть учетные данные, скажем, на 10 минут, даже если я программно удалю их. после этого я в порядке. Я предполагаю, что Apple или любая другая структура, работающая в фоновом режиме, кэширует эти учетные данные для фактического URL-адреса, и мы просто не можем получить доступ к этой части. Кажется, это коррелирует с трюком «#». - person Mike F; 27.10.2011

Я знаю, что это старая тема. Однако единственное, что у меня работает, это использовать разные URL-адреса для разных сертификатов.

Это сработало в моем приложении, так как у меня есть только 2 сертификата (один общий в ресурсах приложения и один пользовательский, загруженный из Интернета после процесса проверки пользователя). В моем случае нет файлов cookie и учетных данных для очистки, поэтому ни одно из решений, которые я нашел в stackoverflow, не сработало.

person Marcin Szulc    schedule 15.02.2013

Я столкнулся с той же проблемой, теперь это работает.

Используя NSURLConnection, эту проблему можно легко исправить, добавив случайное число в конец URL-адреса:

Итак, найдите свой URLRequest и добавьте случайное число к URLRequest.

NSInteger randomNumber = arc4random() % 999;
NSString *requestURL = [NSString stringWithFormat:@"%@?cache=%ld",yourURL,(long)randomNumber];

NSURL *URLRequest = [NSURL URLWithString:requestURL];

И убедитесь, что у вас есть случайное число в конце всех URL-адресов, по которым вы звоните.

person CGR    schedule 09.09.2016