2014-09-10 2 views
14

Zdarzają się uruchamianie usługi sieciowej REST z interfejsem API wymagającym, aby klienci używali uwierzytelniania Basic. Przygotowaliśmy zestaw ładnych próbek w różnych językach, pokazujący, w jaki sposób połączyć się z naszą usługą. Teraz mam przeglądając logi IIS usługi i zobaczyć, że następujący wzór zdarza się dość często:Dlaczego klienci usługi .NET w usłudze REST wyślą każde żądanie bez nagłówków uwierzytelniania, a następnie spróbują go ponownie z nagłówkiem uwierzytelniania?

  • żądanie przyjdzie, zostanie odrzucona z kodem HTTP 401
  • taka sama prośba jest Odesłano i uda

która wygląda jak pierwsza prośba jest wysyłana bez nagłówków Authorization, a następnie druga jest wysyłana z prawymi nagłówkami i kończy się sukcesem. W większości przypadków rekord dziennika zawiera "user-agent", który jest tym samym ciągiem, który wsadziliśmy do naszej próbki .NET.

Zakładam więc, że problem dotyczy tylko programów .NET. Problem nie jest reprodukowany za pomocą naszego przykładowego kodu, więc zakładam, że użytkownicy w jakiś sposób zmodyfikowali kod lub napisali własne od podstaw.

Próbowaliśmy skontaktować się z użytkownikami, ale najwyraźniej nie chcą poświęcać czasu na badania. Więc byłoby miło znaleźć najbardziej prawdopodobny scenariusz, który prowadzi do takiego zachowania programów .NET.

Dlaczego mieliby to robić? Dlaczego nie załączyliby nagłówków za pierwszym razem?

Odpowiedz

31

Jest to domyślne zachowanie klas HttpClient i HttpWebRequest, które są wyświetlane w następujący sposób.

Uwaga: Poniższy tekst wyjaśnia zachowanie nieoptymalne, powodujące problem opisany w pytaniu. Najprawdopodobniej nie powinieneś pisać swojego kodu w ten sposób. Zamiast przewijać poniżej do kodu skorygowanej

W obu przypadkach instancji NetworkCredenatial obiekt i ustawić nazwę użytkownika i hasło nie

var credentials = new NetworkCredential(username, password); 

Jeśli używasz HttpWebRequest - zestaw .Credentials właściwość:

webRequest.Credentials = credentials; 

Jeśli używasz HttpClient - przekaż obiekt poświadczeń do HttpClientHandler (zmieniony kod z here):

var client = new HttpClient(new HttpClientHandler() { Credentials = credentials }) 

Następnie uruchom Fiddlera i uruchom żądanie.będzie można zobaczyć następujące:

  • żądanie jest wysyłane bez Autoryzacji nagłówka
  • usługa odpowiada z HTTP 401 i uwierzytelniania w sieci WWW: Podstawowe realm = „UrRealmHere”
  • żądanie jest Odesłano przy odpowiednim Autoryzacja nagłówka (i uda)

Takie zachowanie jest wyjaśnione here - Clie nt nie wie z góry, że usługa wymaga Podstawowy i próbuje negocjować protokół uwierzytelniania (i jeśli usługa wymaga Digest wysyłanie Podstawowych nagłówków w open jest bezużyteczne i może narazić klienta na szwank).

Uwaga: Tutaj kończy się wyjaśnienie suboptymalnego zachowania i wyjaśnione jest lepsze podejście. Najprawdopodobniej powinieneś użyć kodu poniżej, zamiast kodu z góry.

W przypadkach, gdy wiadomo, że usługa wymaga Podstawowe że dodatkowe żądanie może zostać wyeliminowana w następujący sposób:

nie ustawisz .Credentials, zamiast dodawać nagłówki ręcznie przy użyciu kodu z here. Zakodować nazwę użytkownika i hasło:

var encoded = Convert.ToBase64String(Encoding.ASCII.GetBytes(
    String.Format("{0}:{1}", username, password))); 

Podczas korzystania HttpWebRequest dodać go do nagłówków:

request.Headers.Add("Authorization", "Basic " + encoded); 

i przy użyciu HttpClient dodać go do domyślnych nagłówków:

client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", encoded); 

kiedy to robisz żądanie jest wysyłane za każdym razem z odpowiednimi nagłówkami autoryzacji. Zauważ, że nie powinien ustawić .Credentials, w przeciwnym razie, jeżeli nazwa użytkownika lub hasło jest nieprawidłowe taka sama prośba zostanie wysłana dwukrotnie zarówno czas z niewłaściwych mandatów i za każdym razem oczywiście uzyskując HTTP 401.

+1

To rozwiązanie działa także pozwala ustawić nagłówek Authorization na pierwszym żądaniu, omijając 401 Challenge/Response. Jednak w moim doświadczeniu z HttpClient i HttpClientHandler ustawienie wstępnego uwierzytelnienia działa, ponieważ nagłówek Authorize jest ustawiany przy każdym żądaniu po zakończeniu wyzwania 401 Challenge/Response. Ten artykuł wyjaśnia to dobrze: http://weblog.west-wind.com/posts/2010/Feb/18/NET-WebRequestPreAuthenticate-not-quite-what-it-sounds- like – Philippe

+0

@Philippe: Tak, to działa także. Dziękuję Ci. – sharptooth

+0

Wskazówka: w przypadku proxy należy zamiast tego ustawić nagłówek 'client.DefaultRequestHeaders.ProxyAuthorization'. – stil

Powiązane problemy