Mam aplikację internetową (hostowaną w IIS), która komunikuje się z usługą systemu Windows. Usługa systemu Windows korzysta z interfejsu API sieci Web ASP.Net MVC (samodzielnie hostowana), więc można ją komunikować za pośrednictwem protokołu HTTP przy użyciu formatu JSON. Aplikacja internetowa jest skonfigurowana do podszywania się, a idea polega na tym, że użytkownik, który wysyła żądanie do aplikacji internetowej, powinien być użytkownikiem, którego aplikacja internetowa używa do wysłania żądania do usługi. Struktura wygląda następująco:
(Użytkownik wyróżniony na czerwono to użytkownik, o którym mowa w poniższych przykładach).
Aplikacja internetowa wysyła żądania do usługi Windows za pomocą HttpClient
:
var httpClient = new HttpClient(new HttpClientHandler()
{
UseDefaultCredentials = true
});
httpClient.GetStringAsync("http://localhost/some/endpoint/");
Powoduje to wysłanie żądania do usługi systemu Windows, ale nie przekazuje poprawnie poświadczeń (usługa zgłasza użytkownika jako IIS APPPOOL\ASP.NET 4.0
). Nie tego chcę .
Jeśli zmienię powyższy kod, aby WebClient
zamiast tego używał a, poświadczenia użytkownika są przekazywane poprawnie:
WebClient c = new WebClient
{
UseDefaultCredentials = true
};
c.DownloadStringAsync(new Uri("http://localhost/some/endpoint/"));
Za pomocą powyższego kodu usługa zgłasza użytkownika jako użytkownika, który zgłosił żądanie do aplikacji internetowej.
Co robię źle z HttpClient
implementacją, która powoduje, że nie przekazuje ona poprawnie poświadczeń (lub czy jest to błąd z HttpClient
)?
Powodem, dla którego chcę użyć HttpClient
jest to, że ma async API, które działa dobrze z Task
s, podczas gdy WebClient
asyc API musi być obsługiwane ze zdarzeniami.
źródło
DownloadStringTaskAsync
w .Net 4.5, który może być również używany z async / awaitHttpClient
nie maSetCredentials()
metody. Czy możesz wskazać mi, co masz na myśli?new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseDefaultCredentials = true }
na serwerze sieciowym, do którego dostęp miał użytkownik uwierzytelniony w systemie Windows, a następnie witryna sieci Web uwierzytelniła się dla innego zdalnego zasobu (nie uwierzytelniłaby się bez ustawionej flagi).Odpowiedzi:
Ja też miałem ten sam problem. Opracowałem rozwiązanie synchroniczne dzięki badaniom wykonanym przez @tpeczek w następującym artykule SO: Nie można uwierzytelnić się w usłudze ASP.NET Web Api z HttpClient
Moje rozwiązanie wykorzystuje znak
WebClient
, który, jak poprawnie zauważyłeś, przekazuje poświadczenia bez problemu. PrzyczynąHttpClient
nie jest to, że zabezpieczenia systemu Windows wyłączają możliwość tworzenia nowych wątków na podszywanym koncie (zobacz artykuł SO powyżej).HttpClient
Tworzy nowe wątki za pośrednictwem fabryki zadań, powodując błąd.WebClient
z drugiej strony działa synchronicznie w tym samym wątku, pomijając w ten sposób regułę i przekazując jej poświadczenia.Chociaż kod działa, wadą jest to, że nie będzie działać asynchronicznie.
Uwaga: wymaga pakietu NuGet: Newtonsoft.Json, który jest tym samym, z którego korzysta interfejs WebAPI serializatora JSON.
źródło
Możesz skonfigurować
HttpClient
automatyczne przekazywanie poświadczeń w następujący sposób:źródło
To, co próbujesz zrobić, to zmusić NTLM do przekazania tożsamości na następny serwer, czego nie może zrobić - może wykonać tylko personifikację, która zapewnia tylko dostęp do zasobów lokalnych. Nie pozwoli ci przekroczyć granicy maszyny. Uwierzytelnianie Kerberos obsługuje delegowanie (to, czego potrzebujesz) przy użyciu biletów, a bilet można przekazać dalej, gdy wszystkie serwery i aplikacje w łańcuchu są poprawnie skonfigurowane, a protokół Kerberos jest poprawnie skonfigurowany w domenie. Krótko mówiąc, musisz przejść z używania NTLM na Kerberos.
Więcej informacji na temat dostępnych opcji uwierzytelniania systemu Windows i sposobu ich działania można znaleźć pod adresem : http://msdn.microsoft.com/en-us/library/ff647076.aspx
źródło
WebClient
? To jest rzecz, której nie rozumiem - jeśli nie jest to możliwe, jak to się stało, że się to robi?WebClient
może przekazać poświadczenia NTLM, aleHttpClient
nie może. Mogę to osiągnąć za pomocą samej personifikacji ASP.Net, bez konieczności używania protokołu Kerberos lub przechowywania nazw użytkowników / haseł. Działa to jednak tylko zWebClient
.OK, dziękuję wszystkim współautorom powyżej. Używam .NET 4.6 i mieliśmy ten sam problem. Spędziłem czas na debugowaniu
System.Net.Http
, a konkretnie naHttpClientHandler
, i znalazłem:Więc po ocenie, że
ExecutionContext.IsFlowSuppressed()
mógł być winowajcą, opakowałem nasz kod personifikacji w następujący sposób:Kod wewnątrz
SafeCaptureIdenity
(nie mój błąd w pisowni), chwytaWindowsIdentity.Current()
naszą podrobioną tożsamość. Jest to zauważane, ponieważ teraz tłumimy przepływ. Ze względu na użycie / dispose jest to resetowane po wywołaniu.Teraz wydaje się, że to działa dla nas, uff!
źródło
using (System.Threading.ExecutionContext.SuppressFlow())
i problem został rozwiązany dla mnie!W .NET Core udało mi się uzyskać
System.Net.Http.HttpClient
z,UseDefaultCredentials = true
aby przekazać poświadczenia systemu Windows uwierzytelnionego użytkownika do usługi zaplecza przy użyciuWindowsIdentity.RunImpersonated
.źródło
U mnie zadziałało po skonfigurowaniu użytkownika z dostępem do Internetu w usłudze Windows.
W moim kodzie:
źródło
Ok, więc wziąłem kod Joshouna i uczyniłem go ogólnym. Nie jestem pewien, czy powinienem implementować wzorzec singleton w klasie SynchronousPost. Może ktoś lepiej poinformowany może pomóc.
Realizacja
// Zakładam, że masz swój własny konkretny typ. W moim przypadku najpierw używam kodu z klasą o nazwie FileCategoryKlasa ogólna tutaj. Możesz przekazać dowolny typ
Moje klasy Api wyglądają tak, jeśli jesteś ciekawy
Używam ninject i wzorca repo z jednostką pracy. W każdym razie powyższa klasa ogólna naprawdę pomaga.
źródło