2011-09-19 6 views
16

Szukałem stackoverflow, google, apple i innych miejsc. Podane wskazówki wyglądają obiecująco, ja je zaimplementowałem, ale wydaje mi się, że nie działają one ani nie są wymuszane.Nie można ponownie uwierzytelniać przy użyciu różnych NSURLCredentials (używane są stare usunięte)

Problem: Mam numer NSURLConnection z określonymi poświadczeniami. Następnie mam wylogowanie, w którym usuwam dane uwierzytelniające, obszar ochrony, usuwam wszystkie buforowane odpowiedzi i usuwam wszystkie pliki cookie w sharedHTTPCookieStorage, ale po ponownym wywołaniu mojego uwierzytelnionego żądania kilka sekund później, nawet przy błędnych danych wciąż używam starego (usunięto) poświadczenia

Oto niektóre ekstrakty kod, gdzie poświadczenia są usuwane

 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]; 
      } 
     } 
    } 

I następnie usunąć wszystkie buforowane Odpowiedzi

NSURLCache *sharedCache = [NSURLCache sharedURLCache]; 
    [sharedCache removeAllCachedResponses]; 

I następnie usunąć wszystkie ciasteczka

NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 
    NSArray *cookies = [cookieStorage cookies]; 
    for (NSHTTPCookie *cookie in cookies) { 
     [cookieStorage deleteCookie:cookie]; 
     NSLog(@"deleted cookie"); 
    } 

Próbowałem też stosując żadnych ciasteczka i inne polityki

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]; 

Próbowałem również tę wskazówkę tu specjalnie przechowywania cookies i przekazując je ponownie. http://www.hanspinckaers.com/multiple-nsurlrequests-with-different-cookies. W sieci jest inny blog sugerujący dodanie "#" do każdego adresu URL w celu wymuszenia ponownego uwierzytelnienia, które działa, ale po prostu nie rozwiązuje problemu, ponieważ muszę liczyć się na poświadczenia sesji i możliwość korzystania z zupełnie innych poświadczeń.

Czy jest to błąd lub znany problem i jak naprawdę rozwiązać ten problem ... Mówiąc wprost: Co dokładnie robię źle tutaj?

To naprawdę mnie dręczy i powstrzymuje mnie od kontynuowania pracy.

Byłbym bardzo wdzięczny za wszelkie dane wejściowe!

Wielkie dzięki!

+1

Mam ten sam problem. - Nie mogę uzyskać poświadczeń z pamięci raz włożyłam je w Wywołanie -removeCredential ... wydaje się mieć żadnego efektu. – paulmelnikow

+0

I, o ile jest to warte, moją "poprawką" było zaadaptowanie mojej aplikacji do korzystania z asynchronicznego API, co pozwala mi dostarczać referencje dokładnie w taki sposób, jaki wybieram. – paulmelnikow

+0

Jeśli myślisz, że usunięcie plików cookie i wyczyszczenie pamięci podręcznej "może" nie działa, to innym sposobem byłoby scalenie poświadczeń, identyfikatora użytkownika lub hasła z losowym tekstem, aby logowanie zakończyło się niepowodzeniem do momentu wprowadzenia poprawnego poświadczenia! – Annjawn

Odpowiedz

1

Co jest warte, mam ten sam problem.

Myślę, że to kwestia czasu. Podczas korzystania z symulatora, jeśli czekam 5-10 sekund przed ponownym zalogowaniem, logowanie nie powiedzie się zgodnie z oczekiwaniami. Ponadto, gdy korzystam z rzeczywistego telefonu, rzadko pojawia się problem - co może być funkcją wolniejszego telefonu lub może być błędem w symulatorze.

+0

OK, co brzmi interesująco - myślę, że ma to coś wspólnego z czasem, ale tylko w niewielkim stopniu. Nie zachowuję się tak samo jak ty. Od pewnego czasu nie zajmuję się tym błędem - bezwstydnie restartuję moją aplikację po wylogowaniu:/- w każdym razie nadal mam poświadczenia, powiedzmy 10 minut, nawet jeśli programowo je usunę. po tym nic mi nie jest. Domyślam się, że Apple lub jakiekolwiek ramy działające w tle buforują te poświadczenia do faktycznego adresu URL i po prostu nie możemy uzyskać dostępu do tej części. Wydaje się, że koreluje to ze sztuczką "#". –

3

Wpadłem też na ten problem. Czyszczenie NSURLCredentialStorage wydaje się działać częściowo, ale wydaje się, że muszę poczekać kilka sekund po tym, aby zadziałało. Wykonanie innego żądania HTTP bez oczekiwania powoduje użycie starego nagłówka Authorization.

udało mi się go naprawić poprzez przepuszczenie NSURLCredentialPersistenceNone podczas inicjalizacji moje NSURLCredential:

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

uwaga: spowoduje to 401 wyzwań na każde żądanie HTTP można zrobić z tym NSURLCredential. Nie stanowi to jednak problemu, jeśli odzyskasz pliki cookie, które będą Cię uwierzytelniać.

1

Wiem, że to stary temat. Jednak jedyną rzeczą, która działa dla mnie było użycie różnych adresów URL dla różnych certyfikatów.

Działa w mojej aplikacji, ponieważ mam tylko 2 certyfikaty (jeden ogólny w zasobach aplikacji i jeden zwyczaj pobrany z Internetu po procesie weryfikacji użytkownika). W moim przypadku nie ma plików cookie i żadnych poświadczeń do usunięcia, więc żadne z rozwiązań znalezionych na stackoverflow nie działało.

7

Niestety, nie wydaje się, aby rozwiązać ten problem.

Możesz użyć NSURLCredentialPersistenceNone lub # triku lub możesz zdefiniować metodę delegowania "connectionShouldUseCredentialStorage", aby zwrócić NO. Jeśli robisz to za każdym razem, a twoja aplikacja nigdy nie utrzymuje danych uwierzytelniających dla sesji, to wymusi to wyzwanie na każde żądanie.

W przypadku aplikacji, które wykonują tylko minimalne żądania lub które kończą używanie pliku cookie sesji do uwierzytelnienia, może to działać poprawnie.

W przypadku aplikacji, które wysyłają dużą liczbę żądań, wszystkie te rozwiązania skutkują odpowiedzią 401 na każde żądanie, a dodatkowa reakcja na wyzwanie może zsumować dane i wydajność.

Byłoby miło, gdyby można było przechowywać pamięć referencyjną dla sesji, dopóki nie trzeba się wylogować, a następnie przełączyć na jedną z opcji, ale nie jest to możliwe.

Po zapisaniu poświadczeń raz dla sesji, zostają one buforowane dla całej sesji TLS. To powoduje, że trzeba czekać około 10 minut, aż ta sesja zniknie.

Możesz przeczytać więcej na ten temat na stronie: http://developer.apple.com/library/ios/qa/qa1727/_index.html

dokument ten wymienia ograniczoną obejście, które obejmuje dołączenie „” na końcu nazwy serwera. Jednak nie mogłem tego zrobić.

Poza tym, są to rozwiązania można myślę:

1) Zawsze używaj NSURLCredentialPersistenceNone & connectionShouldUseCredentialStorage obejście, które powinny wygenerować 401s. Dodaj do siebie samego głównego nagłówka uwierzytelniania. Powinno to zapobiec dodatkowym 401 podczas omijania pamięci danych uwierzytelniających. Kod do dodawania tego zezwolenia wygląda mniej więcej tak:

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"] ; 

nie wiem jak miałoby to być realizowane dla innych metod uwierzytelniania, ale przypuszczam, że jest to możliwe.

2) informują użytkownika o problemie i poprosić ich, aby ponownie uruchomić aplikację

3) zaimplementować własną gniazd niskim poziomie w oparciu mechanizm pobierania http że omija CFNetwork całkowicie. Powodzenia z tym:>)

+0

Skończyło się na dodaniu pola nagłówka Authorization do wszystkich moich żądań, zgodnie z sugestią. Nie mogłem znaleźć innego sposobu na uniknięcie problemu, który miałem, gdzie można się było zalogować przy użyciu błędnych danych zaraz po wylogowaniu. – einarnot

4

Właśnie wpadłem na ten problem z AFNetworking. Pracuję z backendem, który wymaga autoryzacji do przekazania w nagłówku. Jednak gdy użytkownik wyloguje się z aplikacji i spróbuje się zalogować ponownie (nawet przy różnych kredytach), otrzymałem błąd z serwera. Moim rozwiązaniem było wyczyszczenie plików cookie mojej aplikacji podczas usuwania authheadera podczas wylogowywania.

- (void)clearAuthorizationHeader { 
    [self.manager.requestSerializer clearAuthorizationHeader]; 
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 
    for (NSHTTPCookie *cookie in [storage cookies]) { 
     [storage deleteCookie:cookie]; 
    } 
} 
+0

właśnie uratowałeś mój dzień - miałem dokładnie ten sam problem z połączeniem oauth w przeciwieństwie do podstawowego, a poświadczenia były ponownie używane. czyszczenie ciasteczek podczas wylogowania działało (oprócz usunięcia referencji, itp.) –

+0

To również działa dla mnie. Dzięki –

0

Miałem do czynienia z tym samym problemem, teraz działa.

Korzystanie NSURLConnection tego problemu może być ustalona łatwo dodając liczbę losową na końcu adresu URL:

Więc wyszukiwania dla URLRequest i dołączyć liczbę losową do URLRequest

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

NSURL *URLRequest = [NSURL URLWithString:requestURL]; 

i uczynić upewnij się, że masz losową liczbę na końcu wszystkich adresów URL, do których dzwonisz.

Powiązane problemy