Autenticación de usuario en API web ASP.NET

150

Este tema ha sido increíblemente confuso para mí. Soy un novato en aplicaciones HTTP pero necesito desarrollar un cliente de iPhone que consuma datos JSON de alguna parte. Elegí Web API de MS porque parecía bastante fácil, pero cuando se trata de autenticar usuarios, las cosas se ponen bastante frustrantes.

Estoy sorprendido de cómo no he podido encontrar un ejemplo claro de cómo autenticar a un usuario desde la pantalla de inicio de sesión hasta usar el Authorizeatributo sobre mis ApiControllermétodos después de varias horas de Google.

Esta no es una pregunta, sino una solicitud de un ejemplo de cómo hacer esto exactamente. He mirado las siguientes páginas:

Si bien estos explican cómo manejar solicitudes no autorizadas, no demuestran claramente algo así como LoginControlleralgo así como solicitar credenciales de usuario y validarlas.

Alguien dispuesto a escribir un buen ejemplo simple o señalarme en la dirección correcta, por favor?

Gracias.

Luis Aguilar
fuente
1
He respondido la misma pregunta sobre esto: stackoverflow.com/questions/11775594/…
cuongle
Para Web Api con asp.net, puede usar el módulo de autenticación de formularios y cookies como lo haría con una aplicación mvc (si lo desea). Entonces, en su código de API web, puede verificar el principal para ver si el usuario ha iniciado sesión, por ejemplo (igual que antes).
Elliot
Mira también mi respuesta para stackoverflow.com/questions/11775594/…
Varun Chatterji
Recomiendo encarecidamente a mucha gente que lea el artículo asp.net/web-api/overview/security/… .
Youngjae

Respuestas:

176

Estoy sorprendido de cómo no he podido encontrar un ejemplo claro de cómo autenticar a un usuario desde la pantalla de inicio de sesión hasta usar el atributo Autorizar sobre mis métodos ApiController después de varias horas de Google.

Eso es porque te estás confundiendo acerca de estos dos conceptos:

  • La autenticación es el mecanismo por el cual los sistemas pueden identificar de forma segura a sus usuarios. Los sistemas de autenticación proporcionan respuestas a las preguntas:

    • Quien es el usuario?
    • ¿Es realmente el usuario quien se representa a sí mismo?
  • La autorización es el mecanismo por el cual un sistema determina qué nivel de acceso debe tener un usuario autenticado en particular para asegurar los recursos controlados por el sistema. Por ejemplo, un sistema de gestión de bases de datos podría diseñarse para proporcionar a ciertas personas específicas la capacidad de recuperar información de una base de datos pero no la capacidad de cambiar los datos almacenados en la base de datos, mientras que les da a otras personas la capacidad de cambiar datos. Los sistemas de autorización proporcionan respuestas a las preguntas:

    • ¿El usuario X está autorizado para acceder al recurso R?
    • ¿El usuario X está autorizado para realizar la operación P?
    • ¿El usuario X está autorizado para realizar la operación P en el recurso R?

El Authorizeatributo en MVC se usa para aplicar reglas de acceso, por ejemplo:

 [System.Web.Http.Authorize(Roles = "Admin, Super User")]
 public ActionResult AdministratorsOnly()
 {
     return View();
 }

La regla anterior permitirá solo usuarios en el Administrador y Súper Usuario roles de accedan al método

Estas reglas también se pueden establecer en el archivo web.config, utilizando el locationelemento Ejemplo:

  <location path="Home/AdministratorsOnly">
    <system.web>
      <authorization>
        <allow roles="Administrators"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

Sin embargo, antes de ejecutar esas reglas de autorización, debe autenticarse en el sitio web actual .

Aunque estos explican cómo manejar solicitudes no autorizadas, no demuestran claramente algo como un LoginController o algo así para solicitar credenciales de usuario y validarlas.

A partir de aquí, podríamos dividir el problema en dos:

  • Autentique a los usuarios cuando consuman los servicios de API web dentro de la misma aplicación web

    Este sería el enfoque más simple, porque confiaría en la autenticación en ASP.Net

    Este es un ejemplo simple:

    Web.config

    <authentication mode="Forms">
      <forms
        protection="All"
        slidingExpiration="true"
        loginUrl="account/login"
        cookieless="UseCookies"
        enableCrossAppRedirects="false"
        name="cookieName"
      />
    </authentication>

    Los usuarios serán redirigidos a la cuenta / ruta de inicio de sesión , allí representaría controles personalizados para solicitar credenciales de usuario y luego configuraría la cookie de autenticación usando:

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
  • Autenticación multiplataforma

    Este caso sería cuando solo exponga servicios de API web dentro de la aplicación web, por lo tanto, tendría otro cliente consumiendo los servicios, el cliente podría ser otra aplicación web o cualquier aplicación .Net (Win Forms, WPF, consola, servicio de Windows, etc)

    Por ejemplo, suponga que consumirá el servicio API web de otra aplicación web en el mismo dominio de red (dentro de una intranet), en este caso podría confiar en la autenticación de Windows proporcionada por ASP.Net.

    <authentication mode="Windows" />

    Si sus servicios están expuestos en Internet, deberá pasar los tokens autenticados a cada servicio de API web.

    Para más información, echa un vistazo a los siguientes artículos:

Jupaol
fuente
3
¡Guauu! Eso es lo que yo llamo una respuesta. Entonces, para concluir. Estoy planeando hacer lo siguiente: 1. Crear un controlador de cuenta con un método de inicio de sesión que reciba el nombre de usuario y la contraseña a través de HTTPS y devuelva el resultado de inicio de sesión y el token. 2. El cliente almacena el token y lo envía como un encabezado (ya no HTTPS) en la solicitud validada por el servidor web. ¿Es ese un buen enfoque? Entonces mi duda final es cómo controlar la manipulación y el vencimiento de los tokens. es posible?
Luis Aguilar
66
@Jupaol Creo que hablo por muchos desarrolladores de API web, no puedo usar la autenticación de formularios porque no tengo un sitio web y los clientes no están usando un navegador, ni puedo usar la autenticación integrada porque los usuarios pueden estar en cualquier parte del mundo en cualquier dispositivo ( de ahí la API web), entonces, ¿qué uso?
markmnl
21
No entiendo por qué esta respuesta recibe tantos votos positivos. No se trata de ASP.NET Web API sino de ASP.NET MVC.
Bastien Vandamme
3
Me gustaría reiterar el comentario de B413 y señalar que esta pregunta específicamente solicita API web
Julien el
66
¿Es esta la respuesta 'incorrecta' más votada en SO? ¡La respuesta en realidad no habla de la API web, que es muy diferente de una aplicación web de mvc! Me gusta @ B413 ¡Estoy totalmente sorprendido!
stt106
15

Si desea autenticarse con un nombre de usuario y contraseña y sin una cookie de autorización , el atributo Autorizar MVC4 no funcionará de inmediato . Sin embargo, puede agregar el siguiente método auxiliar a su controlador para aceptar encabezados de autenticación básicos. Llámalo desde el comienzo de los métodos de tu controlador.

void EnsureAuthenticated(string role)
{
    string[] parts = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(Request.Headers.Authorization.Parameter)).Split(':');
    if (parts.Length != 2 || !Membership.ValidateUser(parts[0], parts[1]))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No account with that username and password"));
    if (role != null && !Roles.IsUserInRole(parts[0], role))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "An administrator account is required"));
}

Desde el lado del cliente, este asistente crea un HttpClientcon el encabezado de autenticación en su lugar:

static HttpClient CreateBasicAuthenticationHttpClient(string userName, string password)
{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(userName + ':' + password)));
    return client;
}
Edward Brey
fuente
Solo quería comentar que estaba buscando una forma sencilla de utilizar el estándar de la industria para pasar las credenciales en el encabezado. Este ejemplo mostró los conceptos básicos tanto del servidor como del lado del cliente y fue todo lo que necesitaba.
da_jokker
9

Estoy trabajando en un proyecto MVC5 / Web API y necesitaba poder obtener autorización para los métodos de la API web. Cuando mi vista de índice se carga por primera vez, hago una llamada al método de API web 'token' que creo que se crea automáticamente.

El código del lado del cliente (CoffeeScript) para obtener el token es:

getAuthenticationToken = (username, password) ->
    dataToSend = "username=" + username + "&password=" + password
    dataToSend += "&grant_type=password"
    $.post("/token", dataToSend).success saveAccessToken

Si tiene éxito, se llama a lo siguiente, que guarda el token de autenticación localmente:

saveAccessToken = (response) ->
    window.authenticationToken = response.access_token

Luego, si necesito hacer una llamada Ajax a un método de API web que tenga la etiqueta [Autorizar], simplemente agrego el siguiente encabezado a mi llamada Ajax:

{ "Authorization": "Bearer " + window.authenticationToken }
ProfNimrod
fuente
De dónde response.access_tokenviene. ¿Lo está configurando desde el código c #?
shashwat
El objeto 'respuesta' es devuelto por el método 'token'.
ProfNimrod
No he estudiado los roles. Este enfoque solo le proporciona un token de acceso para que pueda llamar a los métodos de WebApi decorados con la etiqueta [Autorizar]. Antes del ensamblaje, cuando llama a cualquiera de esos métodos, puede verificar los roles. stackoverflow.com/questions/19689570/mvc-5-check-user-role podría ayudar.
ProfNimrod
¿Y en qué parte de esta solución autenticas a tu usuario?
Craig Brett
El punto final / token se crea automáticamente para cualquier proyecto nuevo de API web. El código detrás de esto es donde se autentica al usuario. Es un poco más complicado si ha agregado un controlador de API web a un proyecto MVC existente.
ProfNimrod