¿Cómo hacer que HttpClient pase las credenciales junto con la solicitud?
Tengo una aplicación web (alojada en IIS) que se comunica con un servicio de Windows. El servicio de Windows utiliza la API web ASP.Net MVC (autohospedada) y, por lo tanto, se puede comunicar a través de http mediante JSON. La aplicación web está configurada para realizar suplantación, 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 siguientes).
La aplicación web realiza solicitudes al servicio de Windows mediante 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 pase .
Si cambio el código anterior para usar a 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 reporta 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 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 asyc de ' debe manejarse con eventos.
Puede configurar HttpClient
para pasar automáticamente credenciales como esta:
var myClient = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
Yo también estaba teniendo este mismo problema. Desarrollé una solución sincrónica gracias a la investigación realizada por @tpeczek en el siguiente artículo SO: No se puede autenticar en el servicio ASP.NET Web Api con HttpClient
Mi solución utiliza un WebClient
, que, como señaló correctamente, pasa las credenciales sin problemas. La razón HttpClient
por la que no funciona es porque la seguridad de Windows desactiva la capacidad de crear nuevos subprocesos en una cuenta suplantada (consulte el artículo SO anterior). HttpClient
Crea nuevos subprocesos a través de Task Factory, lo que provoca 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.
var wi = (System.Security.Principal.WindowsIdentity)HttpContext.Current.User.Identity;
var wic = wi.Impersonate();
try
{
var data = JsonConvert.SerializeObject(new
{
Property1 = 1,
Property2 = "blah"
});
using (var client = new WebClient { UseDefaultCredentials = true })
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
client.UploadData("http://url/api/controller", "POST", Encoding.UTF8.GetBytes(data));
}
}
catch (Exception exc)
{
// handle exception
}
finally
{
wic.Undo();
}
Nota: Requiere el paquete NuGet: Newtonsoft.Json, que es el mismo serializador JSON que utiliza WebAPI.
Lo que está intentando hacer es lograr que NTLM reenvíe la identidad al siguiente servidor, lo cual no puede hacer; solo puede realizar una suplantación que solo le brinda 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. En resumen, debe pasar del 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