ASP.NET Web API Self-Host con Autenticación de Windows


Estoy tratando de utilizar el ASP.NET Opción de auto-host de la API web con autenticación de Windows para que pueda determinar el usuario que ha iniciado sesión y, en última instancia, aceptar o rechazar al usuario en función de su identidad. Aquí está mi código de aplicación de consola:

using System;
using System.Web.Http;
using System.Web.Http.SelfHost;

namespace SelfHost
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = new HttpSelfHostConfiguration("http://myComputerName:8080");
            config.UseWindowsAuthentication = true;

            config.Routes.MapHttpRoute(
                "API Default", "api/{controller}/{id}",
                new { id = RouteParameter.Optional });

            using (HttpSelfHostServer server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();

                Console.WriteLine("Press Enter to quit.");
                Console.ReadLine();
            }
        }
    }
}

Aquí está el controlador:

[Authorize]
public class HelloController : ApiController
{
    public string Get()
    {
        // This next line throws an null reference exception if the Authorize
        // attribute is commented out.
        string userName = Request.GetUserPrincipal().Identity.Name;
        return "Hello " + userName;
    }
}

Edit - Agregué el atributo Authorize, y el depurador muestra que el código dentro del método Get action nunca se invoca. Se devuelve el siguiente HTML:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type></HEAD>
<BODY></BODY></HTML>

Si el atributo Authorize se comenta, Request.GetUserPrincipal().Identity.Name lanza una excepción de referencia nula ya que Request.GetUserPrincipal() rendimientos nulos.

Author: Dave Johnson, 2012-03-05

9 answers

También he tenido este problema y la única solución que se me ocurrió es entregar una configuración Httpselfhosted dedicada:

public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration
{
    public NtlmSelfHostConfiguration(string baseAddress)
        : base(baseAddress)
    { }

    public NtlmSelfHostConfiguration(Uri baseAddress)
        : base(baseAddress)
    { }

    protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
    {
        httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly;
        httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
        return base.OnConfigureBinding(httpBinding);
    }
}

Para usarlo solo necesita cambiar una línea (ya no necesita configurar UseWindowsAuthentication):

var config = new NtlmSelfHostConfiguration("http://myComputerName:8080");

El único problema con este enfoque es que ahora se requiere autenticación para cada solicitud hecha al servidor que está usando esta configuración.

 23
Author: tpeczek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-25 21:46:14

He alojado "Web API" en el servicio de Windows y esto es lo que hice para admitir la autenticación de Windows (básicamente basado en la pregunta anterior, respuestas, algunos artículos relacionados, solo estoy consolidando ya que puede ser útil para otros)

@Servidor HTTP (web api):

Conjunto (referencia: http://msdn.microsoft.com/en-us/library/system.web.http.selfhost.httpselfhostconfiguration.clientcredentialtype(v=vs.118).aspx),

HttpSelfHostConfiguration.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;

@Cliente:

Y luego, como Allan mencionó (arriba), establezca UseDefaultCredentials en true.

Usando HttpClient:

var handler = new HttpClientHandler();
    handler.UseDefaultCredentials = true;
    _httpClient = new HttpClient(handler);

Usando WebClient (referencia: http://msdn.microsoft.com/en-us/library/system.net.webclient.usedefaultcredentials.aspx )

Establezca usedefaultcrednetials de webclient en 'true'.

Saludos cordiales!

 3
Author: Dreamer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-22 19:12:46

Llego un poco tarde a esto. Sin embargo, si está utilizando Owin para auto host y necesita autorización de Windows. En su clase de inicio puede agregar lo siguiente.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        HttpListener listener = (HttpListener)app.Properties["System.Net.HttpListener"];
        listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
    }
}
 3
Author: IdahoSixString,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-26 16:49:36

¿Está seguro de que está pasando por la parte de autenticación? Puede usar fiddler para verificar si las solicitudes están pasando realmente o si el servidor siempre responde con 401 No autorizado (ya que está usando autenticación).

También podría intentar implementar su propio AuthorizeAttribute personalizado y poner puntos de interrupción en él para asegurarse de que se golpea (querrá anular el método OnAuthorization y ver si se golpea).

using System.Web.Http;
public class MyAuth : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        base.OnAuthorization(actionContext); //put breakpoint here
    }
}

También, asegúrese de que está utilizando el Authorize atributo de System.Web.Http, y no de System.Web.Mvc. Ver aquí ¿por qué.

 2
Author: Szilard Muzsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:30:01

¿Has intentado poner la [Authorize] atributo en su controlador?

[Authorize]
public class HelloController : ApiController
 1
Author: Eric King,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-05 20:51:43

Aquí hay un enlace a un breve video que explica cómo usar la autorización.

Http://www.asp.net/web-api/videos/getting-started/authorization

En esencia, use el atributo [Authorize] en la clase, capture el error y devuelva una respuesta HTTP 401 y luego haga que el cliente lo detecte y vaya a la página de inicio de sesión

 1
Author: PTRMark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-07 05:35:55

Solo para agregar, si está utilizando la solución de tpeczek y también utilizando HttpClient, es posible que deba hacer esto:

        var handler = new HttpClientHandler();
        handler.UseDefaultCredentials = true;
        _httpClient = new HttpClient(handler);
 1
Author: Allan Elder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-16 19:49:27

Similar a la respuesta de tpeczek pero actualizada para reflejar el uso de HTTPS. la respuesta de tpeczek no funciona para HTTPS porque la llamada a base.OnConfigureBinding(httpBinding); con HTTPS sobrescribe los cambios. Además, no puede usar httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly; con HTTPS.

Use una configuración HTTPSELFHOST personalizada:

public class NtlmSelfHostConfiguration : HttpSelfHostConfiguration
{
    public NtlmSelfHostConfiguration(string baseAddress)
        : base(baseAddress)
    { }

    public NtlmSelfHostConfiguration(Uri baseAddress)
        : base(baseAddress)
    { }

    protected override BindingParameterCollection OnConfigureBinding(
        HttpBinding httpBinding)
    {
        if (this.BaseAddress.Scheme == Uri.UriSchemeHttps)
        {
            var ret = base.OnConfigureBinding(httpBinding);
            httpBinding.Security.Transport.ClientCredentialType =
                HttpClientCredentialType.Ntlm;
            return ret;
        }

        httpBinding.Security.Mode = HttpBindingSecurityMode.TransportCredentialOnly;
        httpBinding.Security.Transport.ClientCredentialType = 
            HttpClientCredentialType.Ntlm;
        return base.OnConfigureBinding(httpBinding);
    }
}

Entonces, puedes hacer

var config = new NtlmSelfHostConfiguration("http://myComputerName:8080");

O

var config = new NtlmSelfHostConfiguration("https://myComputerName:8443");

Para obtener una configuración para pasar a new HttpSelfHostServer(config)

 1
Author: mheyman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:13

Respuesta relacionada para quién lo necesita, sobre autenticación básica con token

Fusionando algo de ayuda, información, respuestas y un sistema de autoauth que hice para una API Web real, finalmente pude usar etiquetas de roles y atributos para esto. Se hace para la etiqueta de autorización en el encabezado.

Invocación del servidor:

 var config = new HttpSelfHostConfiguration("http://localhost:8080");
            config.UserNamePasswordValidator = new PHVValidator();
            config.Routes.MapHttpRoute(
                "API Default", "{controller}/{id}",
                new { id = RouteParameter.Optional });

            using (HttpSelfHostServer server = new HttpSelfHostServer(config))
            {
                server.OpenAsync().Wait();
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new DominusForm());
            }

Auth Method: (hardcoded for ex. solo, elija usuario, pase y roles desde cualquier lugar)

    public class PHVValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == "admin" && password == "123")
            {
                string[] rolarray = new string[] { "admin" };
               IPrincipal principal = new GenericPrincipal(new GenericIdentity(userName), rolarray);
                Thread.CurrentPrincipal = principal;
            }
        }
    }

Método:

[Authorize(Roles = "admin")]
public HttpResponseMessage Get()
{
     do things
}
 0
Author: Leandro Tupone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-25 17:51:19