Tengo una aplicación web (alojada en IIS) que se comunica con un servicio de Windows. El servicio de Windows mediante el ASP.Net MVC Web API (self-hosted), y por lo tanto puede ser comunicada a través de http con el uso de JSON. La aplicación web está configurado para realizar la suplantación, la idea es que el usuario que hace la petición a la aplicación web debe ser el usuario que utiliza la aplicación web para hacer la solicitud del servicio. La estructura se parece a esto:

Cómo conseguir HttpClient para pasar las credenciales junto con la solicitud?

(El usuario resaltado en rojo es el usuario que se hace referencia en los ejemplos a continuación).


La aplicación web hace que las solicitudes para el servicio de Windows mediante un HttpClient:

var httpClient = new HttpClient(new HttpClientHandler() 
                      {
                          UseDefaultCredentials = true
                      });
httpClient.GetStringAsync("http://localhost/some/endpoint/");

Esto hace que la solicitud para el servicio de Windows, pero no pasa las credenciales a través de correctamente (los informes del servicio al usuario como IIS APPPOOL\ASP.NET 4.0). Esto no es lo que quiero que suceda.

Si puedo cambiar el código de arriba para utilizar un WebClient lugar, las credenciales del usuario que se pasa 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 que el usuario que hizo la petición a la aplicación web.

¿Qué estoy haciendo mal con el HttpClient aplicación que está causando a no pasar las credenciales correctamente (o es un bug con el HttpClient)?

la razón por La que desea utilizar la HttpClient es que tiene una API asincrónicas que funciona bien con Tasks, mientras que el WebClient‘s asyc API debe ser manejado con los eventos.

  • Posibles duplicados de stackoverflow.com/q/10308938/1045728
  • Parece que HttpClient y WebClient considerar diferentes cosas para ser DefaultCredentials. Intenta HttpClient.setCredentials(…) ?
  • Por CIERTO, WebClient ha DownloadStringTaskAsync en .Net 4.5, que también puede ser utilizado con async/await
  • no podemos actualizar .Net 4.5 (todavía), así que por ahora estoy atascado con el .Net 4.0 aplicación.
  • HttpClient no tiene un SetCredentials() método. Puede que me apunte a qué te refieres?
  • HttpClientHandler hace. blogs.msdn.com/b/henrikn/archive/2012/08/07/… – en realidad, el propósito de HttpClientHandler.setCredentials(…) en el comentario original, sino copiado mal el nombre de la clase
  • Ah, ok. No puedo configurar las credenciales de forma explícita el uso de esa llamada ya que se requiere de un ICredentials objetos que no tengo como estoy utilizando la Autenticación de Windows.
  • Parece que este ha sido corregido (.net 4.5.1)? Yo intenté crear new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseDefaultCredentials = true } en un servidor web al que se accede por una autenticación de Windows del usuario, y el sitio web para autenticar otro recurso remoto después de que (no sin autenticar el marcador).

InformationsquelleAutor adrianbanks | 2012-08-31

7 Comentarios

  1. 58

    Yo también tenía este mismo problema. He desarrollado una sincrónico solución gracias a la investigación realizada por @tpeczek en las siguientes PARA el artículo: No puede autenticar a ASP.NET Web de la Api de servicio con HttpClient

    Mi solución utiliza un WebClient que, como ya se señalaba, pasa las credenciales sin problema. La razón HttpClient no funciona es porque de Windows de seguridad de la desactivación de la capacidad para crear nuevos hilos en virtud de una cuenta suplantada (PARA ver el artículo anterior). HttpClient crea nuevos hilos a través de la Tarea de Fábrica causando el error. WebClient por otro lado, se ejecuta de forma sincrónica en el mismo hilo evitando así la regla y el reenvío de sus credenciales.

    A pesar de que el código funciona, lo malo es que no va a trabajar de forma asincrónica.

    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 paquete de NuGet: Newtonsoft.Json, que es el mismo JSON serializador WebAPI usos.

    • Yo hice algo similar en la final, y funciona realmente bien. El asincrónica problema no es un problema, porque quiero que las llamadas a bloque.
  2. 110

    Puede configurar HttpClient para pasar automáticamente las credenciales como este:

    myClient = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true })
    • Yo sé cómo hacer eso. El comportamiento no es lo que quiero (como se indica en la pregunta) – «Esto hace que la solicitud para el servicio de Windows, pero no pasa las credenciales a través de correctamente (los informes del servicio al usuario como IIS APPPOOL\ASP.NET 4.0). Esto no es lo que queremos que suceda.»
    • esto parece soluciono mi problema donde iis sólo tiene habilitada la autenticación de windows. si sólo necesitas un poco de fiar credenciales pasado, este debe hacerlo.
    • No estoy seguro que esto funciona de la misma como WebClient en la suplantación/delegación escenarios. Me sale «El objetivo principal nombre es incorrecta» cuando el uso de HttpClient con la solución anterior, pero utilizando WebClient con una configuración similar pasa las credenciales del usuario a través de.
    • Esto funcionó para mí y los registros muestran de usuario correcto. Aunque, con el doble salto en la foto, yo no esperaba que el trabajo con NTLM como subyacente esquema de autenticación, pero funciona.
    • Cómo hacer lo mismo con la última versión de aspnet core? (2.2). Si alguien sabe…
  3. 24

    Lo que usted está tratando de hacer es conseguir NTLM para el avance de la identidad en el lado del servidor, que no se puede hacer – que sólo pueden hacer la suplantación de que sólo te da el acceso a los recursos locales. No se puede cruzar una máquina de límite. La autenticación Kerberos admite la delegación (lo que necesitas) mediante el uso de billetes, y el billete puede ser enviada cuando todos los servidores y aplicaciones en la cadena están configurados correctamente y Kerberos está configurado correctamente en el dominio.
    Así que, en resumen usted necesita para pasar de utilizar NTLM, Kerberos.

    Para más información sobre la Autenticación de Windows opciones disponibles para usted y cómo funcionan iniciar en:
    http://msdn.microsoft.com/en-us/library/ff647076.aspx

    • BlackSpy es derecho, básicamente lo que hace es describir un escenario de delegación que es algo que el Windows Característicos de la Fundación maneja como se describe en este artículo
    • «NTLM para el avance de la identidad en el lado del servidor, que ella no puede hacer» – ¿cómo se hace esto cuando se utiliza WebClient? Esta es la cosa que no entiendo – si no es posible, ¿cómo es que está de hacerlo?
    • Cuando se utiliza el cliente web es todavía sólo una conexión entre el cliente y el servidor. Se puede suplantar la identidad del usuario en el servidor (1 salto), pero no puede reenviar las credenciales en otro equipo (2 saltos de cliente a servidor al 2 de servidor). Para que usted necesita delegación.
    • No entiendo tu respuesta. Con WebClient, las credenciales recibidas por el servicio web son aquellos de usuario X. Cuando se utiliza el HttpClient, las credenciales son el grupo de aplicación de IIS. Quiero que el WebClient comportamiento, pero en el HttpClient.
    • La única manera de lograr lo que usted está tratando de hacer en la manera que lo estamos tratando de hacer es conseguir que el usuario escriba su nombre de usuario y la contraseña en un cuadro de diálogo personalizado en su ASP.NET aplicación, almacenan como cadenas de caracteres y, a continuación, utilice para establecer su identidad cuando se conecta a la Web de la API de proyecto. De lo contrario, deberá colocar NTLM y mover a Kerberos, así que usted puede pasar el Kerboros billete a través de la Web de la API de proyecto. Te recomiendo la lectura de el enlace que he adjuntado en mi respuesta original. Lo que estamos tratando de hacer requiere una sólida comprensión de la autenticación de windows antes de comenzar.
    • Tengo un montón de experiencia con la Autenticación de Windows. Lo que estoy tratando de entender es por qué el WebClient puede pasar en las credenciales NTLM, pero la HttpClient no. Me puede lograr esto mediante ASP.Net la suplantación solo, y no tener que usar Kerberos o para almacenar nombres de usuario/contraseñas. Sin embargo, esto solo funciona con WebClient.
    • Debe ser imposible de suplantar a través de más de 1 salto sin pasar el nombre de usuario y contraseña alrededor de texto. rompe las reglas de la representación, y NTLM no se lo permite. WebClient permite salto 1 salto porque pasar las credenciales y ejecutar como usuario en la caja. Si usted mira los registros de seguridad verá el inicio de sesión – el usuario inicia sesión en el sistema. No se puede, a continuación, ejecute como usuario de la máquina a menos que usted ha pasado las credenciales de texto y el uso de otro webclient instancia para iniciar sesión en el siguiente cuadro.
    • Cuando usted dice «UseDefaultCredentials = true», NTLM se le impide pasar las credenciales al siguiente servidor de la cadena. Sólo Kerberos está permitido hacer esto.
    • Yo finalmente lo hizo. Este es de dos artículos que me han ayudado : bugfree.ns/blog/2016/05/18/… blogs.msdn.microsoft.com/friis/2009/12/31/…
    • Creo que la respuesta es que no son en realidad mediante NTLM cuando las credenciales se reenvían a un segundo servidor si te das cuenta o no. Si de repente se comenzó a trabajar para su debido Kerberos. Kerberos ahora es el valor predeterminado de configuración de dominios de AD y ha estado disponible en la continua evolución de las formas dentro de AD, ya Server 2003. Siendo ese el caso NTLM también está presente en la mayoría de las implementaciones de la EA como una opción alternativa si el protocolo Kerberos no logran resolver una solicitud. Así que antes de continuar para solucionar este problema, asegúrese de Kerberos está configurado correctamente en el ANUNCIO!

  4. 11

    OK, así que gracias a todos los colaboradores de arriba. Estoy usando .NET 4.6 y también hemos tenido el mismo problema. Pasé un tiempo de depuración System.Net.Http, específicamente el HttpClientHandler, y encontró lo siguiente:

        if (ExecutionContext.IsFlowSuppressed())
        {
          IWebProxy webProxy = (IWebProxy) null;
          if (this.useProxy)
            webProxy = this.proxy ?? WebRequest.DefaultWebProxy;
          if (this.UseDefaultCredentials || this.Credentials != null || webProxy != null && webProxy.Credentials != null)
            this.SafeCaptureIdenity(state);
        }

    Así que después de la evaluación que el ExecutionContext.IsFlowSuppressed() podría haber sido la culpable, me envuelve nuestra Suplantación de código como sigue:

    using (((WindowsIdentity)ExecutionContext.Current.Identity).Impersonate())
    using (System.Threading.ExecutionContext.SuppressFlow())
    {
        //HttpClient code goes here!
    }

    El código dentro de SafeCaptureIdenity (no es mi error de ortografía), agarra WindowsIdentity.Current() que es nuestra identidad suplantada. Esto es de ser recogido, porque ahora estamos en la supresión del flujo. Debido al uso o disponer que se reinicia después de la invocación.

    Ahora parece que funciona para nosotros, ufff!

    • Muchas gracias por hacer este análisis. Este solucionado mi situación. Ahora mi Identidad pasa a través correctamente a la otra aplicación web! Me has salvado de horas de trabajo! Me sorprende que no está más en el contador.
  5. 6

    En .NET Core, me las arreglé para conseguir un System.Net.Http.HttpClient con UseDefaultCredentials = true para pasar a través del usuario autenticado credenciales de Windows para un fondo de servicio mediante el uso de WindowsIdentity.RunImpersonated.

    HttpClient client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true } );
    HttpResponseMessage response = null;
    
    if (identity is WindowsIdentity windowsIdentity)
    {
        await WindowsIdentity.RunImpersonated(windowsIdentity.AccessToken, async () =>
        {
            var request = new HttpRequestMessage(HttpMethod.Get, url)
            response = await client.SendAsync(request);
        });
    }
  6. 4

    A mí me funcionó después de configurar un usuario con acceso a internet en el servicio de Windows.

    En mi código:

    HttpClientHandler handler = new HttpClientHandler();
    handler.Proxy = System.Net.WebRequest.DefaultWebProxy;
    handler.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
    .....
    HttpClient httpClient = new HttpClient(handler)
    .... 
  7. 3

    Ok, así que tomó Joshoun código y lo hizo genéricos. No estoy seguro de si debo implementar el patrón singleton en SynchronousPost clase. Tal vez alguien más knowledgeble puede ayudar.

    Aplicación

    //Supongo que tiene su propio tipo concreto. En mi caso he estoy usando el primer código con una clase llamada FileCategory

    FileCategory x = new FileCategory { CategoryName = "Some Bs"};
    SynchronousPost<FileCategory>test= new SynchronousPost<FileCategory>();
    test.PostEntity(x, "/api/ApiFileCategories"); 

    Clase genérica aquí. Puede pasar cualquier tipo

     public class SynchronousPost<T>where T :class
        {
            public SynchronousPost()
            {
                Client = new WebClient { UseDefaultCredentials = true };
            }
    
            public void PostEntity(T PostThis,string ApiControllerName)//The ApiController name should be "/api/MyName/"
            {
                //this just determines the root url. 
                Client.BaseAddress = string.Format(
             (
                System.Web.HttpContext.Current.Request.Url.Port != 80) ? "{0}://{1}:{2}" : "{0}://{1}",
                System.Web.HttpContext.Current.Request.Url.Scheme,
                System.Web.HttpContext.Current.Request.Url.Host,
                System.Web.HttpContext.Current.Request.Url.Port
               );
                Client.Headers.Add(HttpRequestHeader.ContentType, "application/json;charset=utf-8");
                Client.UploadData(
                                     ApiControllerName, "Post", 
                                     Encoding.UTF8.GetBytes
                                     (
                                        JsonConvert.SerializeObject(PostThis)
                                     )
                                 );  
            }
            private WebClient Client  { get; set; }
        }

    Mi Api classs se parece a esto, si usted es curioso

    public class ApiFileCategoriesController : ApiBaseController
    {
        public ApiFileCategoriesController(IMshIntranetUnitOfWork unitOfWork)
        {
            UnitOfWork = unitOfWork;
        }
    
        public IEnumerable<FileCategory> GetFiles()
        {
            return UnitOfWork.FileCategories.GetAll().OrderBy(x=>x.CategoryName);
        }
        public FileCategory GetFile(int id)
        {
            return UnitOfWork.FileCategories.GetById(id);
        }
        //Post api/ApileFileCategories
    
        public HttpResponseMessage Post(FileCategory fileCategory)
        {
            UnitOfWork.FileCategories.Add(fileCategory);
            UnitOfWork.Commit(); 
            return new HttpResponseMessage();
        }
    }

    Estoy usando ninject, y repo patrón con la unidad de trabajo. De todos modos, la clase genérica de arriba realmente ayuda.

Dejar respuesta

Please enter your comment!
Please enter your name here