Tengo una aplicación web (alojada en IIS) que habla con un servicio de Windows. El servicio de Windows está utilizando la API web ASP.Net MVC (autohospedado), por lo que se puede comunicar a través de http utilizando JSON. La aplicación web está configurada para suplantar, la idea es que el usuario que realiza la solicitud a la aplicación web debe ser el usuario que la aplicación web utiliza para realizar la solicitud al servicio. La estructura se ve así:
(El usuario resaltado en rojo es el usuario al que se hace referencia en los ejemplos a continuación).
La aplicación web realiza solicitudes al servicio de Windows utilizando un HttpClient
:
var httpClient = new HttpClient(new HttpClientHandler()
{
UseDefaultCredentials = true
});
httpClient.GetStringAsync("http://localhost/some/endpoint/");
Esto realiza la solicitud al servicio de Windows, pero no pasa las credenciales correctamente (el servicio informa al usuario como IIS APPPOOL\ASP.NET 4.0
). Esto no es lo que quiero que suceda .
Si cambio el código anterior para usar un WebClient
en su lugar, las credenciales del usuario se pasan correctamente:
WebClient c = new WebClient
{
UseDefaultCredentials = true
};
c.DownloadStringAsync(new Uri("http://localhost/some/endpoint/"));
Con el código anterior, el servicio informa al usuario como el usuario que realizó la solicitud a la aplicación web.
¿Qué estoy haciendo mal con la HttpClient
implementación que hace que no pase las credenciales correctamente (o es un error con el HttpClient
)?
La razón por la que quiero usar HttpClient
es que tiene una API asíncrona que funciona bien con Task
s, mientras que la WebClient
API asíncrona debe manejarse con eventos.
fuente
DownloadStringTaskAsync
en .Net 4.5, que también se puede usar con async / awaitHttpClient
no tiene unSetCredentials()
método. ¿Puedes señalarme a qué te refieres?new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseDefaultCredentials = true }
en un servidor web al que accedía un usuario autenticado de Windows, y el sitio web se autenticó para otro recurso remoto después de eso (no se autenticaría sin el indicador establecido).Respuestas:
También estaba teniendo este mismo problema. Desarrollé una solución síncrona gracias a la investigación realizada por @tpeczek en el siguiente artículo de SO: No se puede autenticar al servicio ASP.NET Web Api con HttpClient
Mi solución utiliza un
WebClient
, que como notó correctamente, pasa las credenciales sin problemas. La razón por laHttpClient
que no funciona es porque la seguridad de Windows deshabilita la capacidad de crear nuevos subprocesos bajo una cuenta suplantada (consulte el artículo SO anterior).HttpClient
Crea nuevos subprocesos a través de la Fábrica de tareas, lo que causa el error.WebClient
por otro lado, se ejecuta sincrónicamente en el mismo hilo, evitando así la regla y reenviando sus credenciales.Aunque el código funciona, la desventaja es que no funcionará de forma asíncrona.
Nota: Requiere el paquete NuGet: Newtonsoft.Json, que es el mismo serializador JSON que utiliza WebAPI.
fuente
Puede configurar
HttpClient
para pasar automáticamente credenciales como esta:fuente
Lo que está tratando de hacer es hacer que NTLM reenvíe la identidad al siguiente servidor, lo que no puede hacer: solo puede suplantar lo que solo le da acceso a los recursos locales. No te permitirá cruzar el límite de una máquina. La autenticación Kerberos admite la delegación (lo que necesita) mediante el uso de tickets, y el ticket se puede reenviar cuando todos los servidores y aplicaciones de la cadena están configurados correctamente y Kerberos está configurado correctamente en el dominio. Entonces, en resumen, debe cambiar el uso de NTLM a Kerberos.
Para obtener más información sobre las opciones de autenticación de Windows disponibles y cómo funcionan, comience en: http://msdn.microsoft.com/en-us/library/ff647076.aspx
fuente
WebClient
? Esto es lo que no entiendo: si no es posible, ¿cómo es que lo está haciendo?WebClient
pueden transmitir las credenciales de NTLM, peroHttpClient
no pueden. Puedo lograr esto usando la suplantación de ASP.Net solo, y sin tener que usar Kerberos o almacenar nombres de usuario / contraseñas. Sin embargo, esto solo funciona conWebClient
.OK, así que gracias a todos los contribuyentes anteriores. Estoy usando .NET 4.6 y también tuvimos el mismo problema. Pasé tiempo depurando
System.Net.Http
, específicamente elHttpClientHandler
, y encontré lo siguiente:Entonces, después de evaluar que el
ExecutionContext.IsFlowSuppressed()
culpable podría haber sido el culpable, envolví nuestro código de suplantación de la siguiente manera:El código dentro de
SafeCaptureIdenity
(no es mi error de ortografía), agarraWindowsIdentity.Current()
cuál es nuestra identidad suplantada. Esto se está recogiendo porque ahora estamos suprimiendo el flujo. Debido al uso / disposición, esto se restablece después de la invocación.Ahora parece funcionar para nosotros, ¡uf!
fuente
using (System.Threading.ExecutionContext.SuppressFlow())
y el problema se resolvió por mí!En .NET Core, logré obtener una
System.Net.Http.HttpClient
conUseDefaultCredentials = true
para pasar las credenciales de Windows del usuario autenticado a un servicio de fondo mediante el usoWindowsIdentity.RunImpersonated
.fuente
Me funcionó después de configurar un usuario con acceso a Internet en el servicio de Windows.
En mi código:
fuente
Ok, tomé el código de Joshoun y lo hice genérico. No estoy seguro de si debería implementar el patrón singleton en la clase SynchronousPost. Quizás alguien más conocedor pueda ayudar.
Implementación
// Supongo que tienes tu propio tipo concreto. En mi caso, estoy usando el código primero con una clase llamada FileCategoryClase genérica aquí. Puedes pasar cualquier tipo
Mis clases de Api se ven así, si tienes curiosidad
Estoy usando ninject y repo pattern con unidad de trabajo. De todos modos, la clase genérica anterior realmente ayuda.
fuente