Autenticación API web ASP.NET MVC 4 con proveedor de membresía

Tengo un proyecto ASP.NET MVC 4 usando la API web. En el controlador, he establecido que la clase requiera autorización utilizando el atributo [Autorizar]. Para la autenticación, estoy usando el proveedor de membresía de ASP.NET y tengo configurado mi Web.Config para usar la autenticación de “Formularios”. Aquí es donde estoy atrapado:

Todo funciona bien hasta el punto en que he terminado de probar la API y quiero asegurar el controlador con el atributo [Autorizar] para poder comenzar a probar la autenticación contra los usuarios de mi Proveedor de Membresía. Así que enciendo el Fiddler y hago la misma llamada agregando el atributo de Autorización: Básico junto con un nombre de usuario: contraseña de mi proveedor de membresía, así:

enter image description here

La respuesta que recibo es 401 no autorizada y en “Auth” obtengo “No hay encabezado WWW-Authenticate presente”. Entonces me doy cuenta de que la API está buscando una clave codificada SHA1. Así que arranco un generador SHA1 de una búsqueda y obtengo un hash para mi nombre de usuario: contraseña y actualizo mi Encabezado de solicitud así:

enter image description here

Esto tampoco funciona y obtengo los mismos resultados. También obviamente necesito algún tipo de “clave secreta compartida” para usar con el servidor para decodificar mi nombre de usuario / contraseña.

Entonces mis preguntas:

  1. ¿Cómo obtengo esta clave del servidor (o en este caso Virtual IIS ejecutándose VS 2012).
  2. ¿Cómo puedo usar esto para hacer llamadas autenticadas en Fiddler usando nombres de usuario / contraseñas de un proveedor de membresía de ASP.NET?
  3. ¿Cómo usaré esto en mi aplicación cliente para hacer las mismas llamadas (aplicación C # WPF)?
  4. ¿Es esto mejor práctico cuando se combina con SSL en mis llamadas HTTP? Si no es lo que es?

¡Gracias por adelantado!

Puede usar autenticación básica con SSL. Del lado del servidor podríamos escribir un controlador de delegación personalizado que verificará las credenciales consultando al proveedor de membresía que registramos, y si es válido, recupere las funciones y establezca el principal actual:

public class BasicAuthenticationMessageHandler : DelegatingHandler { protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var authHeader = request.Headers.Authorization; if (authHeader == null) { return base.SendAsync(request, cancellationToken); } if (authHeader.Scheme != "Basic") { return base.SendAsync(request, cancellationToken); } var encodedUserPass = authHeader.Parameter.Trim(); var userPass = Encoding.ASCII.GetString(Convert.FromBase64String(encodedUserPass)); var parts = userPass.Split(":".ToCharArray()); var username = parts[0]; var password = parts[1]; if (!Membership.ValidateUser(username, password)) { return base.SendAsync(request, cancellationToken); } var identity = new GenericIdentity(username, "Basic"); string[] roles = Roles.Provider.GetRolesForUser(username); var principal = new GenericPrincipal(identity, roles); Thread.CurrentPrincipal = principal; if (HttpContext.Current != null) { HttpContext.Current.User = principal; } return base.SendAsync(request, cancellationToken); } } 

A continuación, registramos este controlador en Application_Start :

 GlobalConfiguration.Configuration.MessageHandlers.Add( new BasicAuthenticationMessageHandler() ); 

Ahora podríamos tener un controlador Api que se decorará con el atributo [Autorizar] para garantizar que solo los usuarios autenticados puedan acceder a sus acciones:

 [Authorize] public class ValuesController : ApiController { public string Get() { return string.Format("Hello {0}", User.Identity.Name); } } 

Bien, ahora veamos un ejemplo de cliente:

 using System; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text; class Program { static void Main() { // since for testing purposes I am using IIS Express // with an invalid SSL certificate I need to desactivate // the check for this certificate. ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true; using (var client = new HttpClient()) { var buffer = Encoding.ASCII.GetBytes("john:secret"); var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(buffer)); client.DefaultRequestHeaders.Authorization = authHeader; var task = client.GetAsync("https://localhost:44300/api/values"); if (task.Result.StatusCode == HttpStatusCode.Unauthorized) { Console.WriteLine("wrong credentials"); } else { task.Result.EnsureSuccessStatusCode(); Console.WriteLine(task.Result.Content.ReadAsAsync().Result); } } } }