43

Mam projekt ASP.NET MVC 4 za pomocą interfejsu API WWW. Na kontrolerze ustawiłem klasę wymagającą autoryzacji za pomocą atrybutu [Autoryzuj]. Do uwierzytelniania używam dostawcy członkostwa ASP.NET i mam ustawiony zestaw Web.Config do używania uwierzytelniania "Formularze". Tutaj utknąłem:ASP.NET MVC 4 Web API Authentication z dostawcą członkostwa

Wszystko działa dobrze, aż do momentu, w którym skończyłem testowanie interfejsu API i chcę zabezpieczyć kontroler za pomocą atrybutu [Authorize], aby móc rozpocząć testowanie uwierzytelniania dla użytkowników w moim Dostawca członkostwa. Więc odpalić Skrzypek i dokonać takiego samego połączenia dodając pozwolenia: Podstawowe atrybutu wraz z Nazwa użytkownika: Hasło od mojego dostawcy członkostwa tak:

enter image description here

odpowiedzi otrzymuję jest 401 nieuprawnione i pod „Auth” Otrzymuję "Brak nagłówka uwierzytelniania WWW". Wtedy zdaję sobie sprawę, że API szuka klucza kodowanego SHA1. Więc odpalić generator SHA1 z wyszukiwania i uzyskać hash dla mojego Nazwa użytkownika: Hasło i zaktualizować nagłówka żądania tak:

enter image description here

To nie działa albo i uzyskać takie same wyniki. Poza tym oczywiście potrzebuję jakiegoś "wspólnego sekretnego klucza", aby użyć go do odszyfrowania mojej nazwy użytkownika/hasła.

więc moje pytania:

  1. Jak mogę dostać ten klucz z serwera (lub w tym przypadku wirtualnego IIS zjechania VS 2012).
  2. Jak używać tego do wykonywania uwierzytelnionych wywołań w Skrzypek przy użyciu nazw użytkowników/haseł od dostawcy członkostwa ASP.NET.
  3. Jak korzystać z tego w mojej aplikacji klienckiej, aby wykonać te same wywołania (aplikacja C# WPF).
  4. Czy jest to najlepsze rozwiązanie w połączeniu z protokołem SSL podczas wywołań HTTP? Jeśli nie, to co jest?

Z góry dziękuję!

Odpowiedz

67

Możesz użyć basic authentication z SSL. Po stronie serwera możemy napisać klasę obsługi przekazał mu uprawnienia, które zweryfikuje poświadczenia przez odpytywanie dostawcy memebership że zarejestrowany, a jeżeli ważny, pobierać role i ustawić aktualną Zleceniodawca:

public class BasicAuthenticationMessageHandler : DelegatingHandler 
{ 
    protected override Task<HttpResponseMessage> 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); 
    } 
} 

Następnie zarejestrować ten moduł obsługi w Application_Start:

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

Teraz możemy mieć kontroler API, które zostaną ozdobione [Autoryzacja] przypisują do zapewnienia, że ​​tylko uwierzytelnionym użytkownikom dostęp do jego działania:

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

Dobra, teraz spójrzmy na klienta próbki:

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<string>().Result); 
      } 
     } 
    } 
} 
+0

Dzięki Darin, to jest dokładnie to, co potrzebne! – CodeAbundance

+0

'User.Identity.Name' w metodzie sterownika jest dla mnie pusta,' User.Identity.IsAuthenticated' to "false". W debugerze widzę, że 'Thread.CurrentPrincipal' jest ustawiony na nazwę użytkownika z poprawną nazwą użytkownika i rolami w procedurze obsługi komunikatów. Również '[Authorization (Roles = ...)] 'atrybut jest respektowany: Jeśli użyję użytkownika z niewłaściwymi rolami, otrzymam nieautoryzowaną odpowiedź i nie osiągnę metody kontrolera. Ale 'User.Identity' nie ma wartości, którą ustawiłem w module obsługi komunikatów. Czy masz pojęcie, co może być nie tak? – Slauma

+0

@Slauma, nie mogę tego odtworzyć. Może mógłbyś zacząć nowy wątek wyjaśniający krok po kroku, jak odtworzyć problem (zaczynając od pustego projektu oczywiście). –

Powiązane problemy