Uwierzytelnianie użytkowników w ASP.NET Web API

150

Ten temat był dla mnie niesamowicie zagmatwany. Jestem nowicjuszem w aplikacjach HTTP, ale muszę opracować klienta iPhone'a, który pobiera skądś dane JSON. Wybrałem Web API od MS, ponieważ wydawało się to łatwe, ale jeśli chodzi o uwierzytelnianie użytkowników, sprawy stają się dość frustrujące.

Jestem zdumiony, jak nie udało mi się znaleźć wyraźnego przykładu uwierzytelniania użytkownika od samego ekranu logowania do użycia Authorizeatrybutu w moich ApiControllermetodach po kilku godzinach Google.

To nie jest pytanie, ale prośba o przykład, jak dokładnie to zrobić. Spojrzałem na następujące strony:

Mimo że wyjaśniają, jak obsługiwać nieautoryzowane żądania, nie pokazują wyraźnie czegoś takiego jak a LoginControllerlub czegoś podobnego, aby poprosić o poświadczenia użytkownika i zweryfikować je.

Czy ktoś chce napisać miły prosty przykład lub wskazać mi właściwy kierunek?

Dzięki.

Luis Aguilar
źródło
1
Odpowiedziałem na to samo pytanie na ten temat: stackoverflow.com/questions/11775594/ ...
cuongle
W przypadku interfejsu API sieci Web z platformą asp.net możesz po prostu użyć modułu cookie i uwierzytelniania formularzy, tak jak w przypadku aplikacji MVC (jeśli chcesz). Tak więc w kodzie interfejsu API sieci Web można sprawdzić nazwę użytkownika, aby na przykład sprawdzić, czy użytkownik jest zalogowany (tak samo jak poprzednio).
Elliot
Spójrz także na moją odpowiedź na stackoverflow.com/questions/11775594/ ...
Varun Chatterji
Zdecydowanie polecam wielu osobom przeczytanie artykułu asp.net/web-api/overview/security/… .
Youngjae

Odpowiedzi:

176

Jestem zdumiony, jak nie udało mi się znaleźć wyraźnego przykładu uwierzytelniania użytkownika od samego ekranu logowania do użycia atrybutu Authorize na moich metodach ApiController po kilku godzinach Googling.

To dlatego, że mylisz się co do tych dwóch pojęć:

  • Uwierzytelnianie to mechanizm, za pomocą którego systemy mogą bezpiecznie identyfikować swoich użytkowników. Systemy uwierzytelniania odpowiadają na pytania:

    • Kim jest użytkownik?
    • Czy użytkownik naprawdę jest tym, za kogo się przedstawia?
  • Autoryzacja to mechanizm, za pomocą którego system określa, jaki poziom dostępu powinien mieć dany uwierzytelniony użytkownik do zabezpieczonych zasobów kontrolowanych przez system. Na przykład system zarządzania bazą danych może być zaprojektowany w taki sposób, aby zapewnić określonym określonym osobom możliwość pobierania informacji z bazy danych, ale nie możliwość zmiany danych przechowywanych w bazie danych, dając jednocześnie innym osobom możliwość zmiany danych. Systemy autoryzacji udzielają odpowiedzi na pytania:

    • Czy użytkownik X jest upoważniony do dostępu do zasobu R?
    • Czy użytkownik X jest upoważniony do wykonania operacji P?
    • Czy użytkownik X jest upoważniony do wykonania operacji P na zasobie R?

AuthorizeAtrybut w MVC służy do zastosowania reguł dostępu, na przykład:

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

Powyższa reguła zezwala na dostęp do metody tylko użytkownikom w rolach administratora i superużytkownika

Reguły te można również ustawić w pliku web.config za pomocą locationelementu. Przykład:

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

Jednak zanim te reguły autoryzacji zostaną wykonane, musisz zostać uwierzytelniony w bieżącej witrynie internetowej .

Mimo że wyjaśniają one, jak obsługiwać nieautoryzowane żądania, nie pokazują wyraźnie czegoś takiego jak LoginController lub czegoś podobnego, aby poprosić o poświadczenia użytkownika i zweryfikować je.

Stąd możemy podzielić problem na dwie części:

  • Uwierzytelnij użytkowników podczas korzystania z usług interfejsu API sieci Web w tej samej aplikacji sieci Web

    Byłoby to najprostsze podejście, ponieważ polegałoby na uwierzytelnianiu w ASP.Net

    Oto prosty przykład:

    Web.config

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

    Użytkownicy zostaną przekierowani do konta / trasy logowania , gdzie wyrenderujesz niestandardowe kontrolki, aby poprosić o poświadczenia użytkownika, a następnie ustawisz plik cookie uwierzytelniania za pomocą:

        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);
  • Uwierzytelnianie międzyplatformowe

    Taki przypadek miałby miejsce, gdy udostępniasz tylko usługi interfejsu API sieci Web w aplikacji sieci Web, w związku z czym inny klient korzystałby z usług, klientem mogłaby być inna aplikacja internetowa lub dowolna aplikacja .Net (formularze Win, WPF, konsola, usługa systemu Windows, itp)

    Na przykład załóżmy, że będziesz korzystać z usługi interfejsu API sieci Web z innej aplikacji internetowej w tej samej domenie sieciowej (w obrębie intranetu), w tym przypadku możesz polegać na uwierzytelnianiu systemu Windows zapewnianym przez ASP.Net.

    <authentication mode="Windows" />

    Jeśli Twoje usługi są ujawniane w Internecie, musisz przekazać uwierzytelnione tokeny do każdej usługi interfejsu API sieci Web.

    Więcej informacji znajdziesz w następujących artykułach:

Jupaol
źródło
3
Łał! To właśnie nazywam odpowiedzią. A więc podsumowując. Planuję wykonać następujące czynności: 1. Utworzyć kontroler konta za pomocą metody logowania, która odbierze nazwę użytkownika i hasło przez HTTPS i zwróci wynik logowania oraz token. 2. Klient przechowuje token i wysyła go jako nagłówek (już nie HTTPS) w żądaniu, które jest sprawdzane przez serwer WWW. Czy to dobre podejście? Wtedy moja ostatnia wątpliwość dotyczy tego, jak kontrolować fałszowanie i wygaśnięcie tokena. czy to możliwe?
Luis Aguilar
6
@Jupaol Myślę, że mówię do wielu programistów Web API, nie mogę używać uwierzytelniania za pomocą formularzy, ponieważ nie mam strony internetowej, a klienci nie używają przeglądarki, ani nie mogę używać zintegrowanego uwierzytelniania, ponieważ użytkownicy mogą znajdować się w dowolnym miejscu na świecie na dowolnym urządzeniu ( stąd Web API), więc czego używam?
markmnl
21
Nie rozumiem, dlaczego ta odpowiedź zyskała tyle pozytywnych głosów. Nie chodzi o ASP.NET Web API, ale o ASP.NET MVC.
Bastien Vandamme
3
Chciałbym powtórzyć komentarz B413 i zwrócić uwagę, że to pytanie dotyczy specjalnie interfejsu API sieci Web
Julien
6
Czy jest to najbardziej pozytywna odpowiedź „zła” na SO? Odpowiedź tak naprawdę nie mówi o interfejsie API sieciowym, który bardzo różni się od aplikacji internetowej MVC! Podobnie jak @ B413, jestem całkowicie zszokowany!
stt106
15

Jeśli chcesz, aby uwierzytelnić przed nazwą użytkownika i hasłem oraz bez ciasteczka autoryzacji The MVC4 Autoryzuj atrybut nie będzie działać po wyjęciu z pudełka. Możesz jednak dodać następującą metodę pomocnika do kontrolera, aby akceptować nagłówki podstawowego uwierzytelniania. Wywołaj to od początku metod swojego kontrolera.

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"));
}

Po stronie klienta ten pomocnik tworzy HttpClientz umieszczonym nagłówkiem uwierzytelniania:

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
źródło
Chciałem tylko skomentować, że szukałem prostego sposobu na użycie standardu branżowego do przekazywania poświadczeń w nagłówku. Ten przykład pokazał podstawy zarówno po stronie serwera, jak i klienta i był wszystkim, czego potrzebowałem.
da_jokker
9

Pracuję nad projektem MVC5 / Web API i potrzebuję możliwości uzyskania autoryzacji dla metod Web Api. Kiedy mój widok indeksu jest ładowany po raz pierwszy, wywołuję metodę Web API „token”, która, jak sądzę, jest tworzona automatycznie.

Kod po stronie klienta (CoffeeScript) do pobrania tokena to:

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

Jeśli się powiedzie, zostanie wywołane następujące polecenie, które zapisuje token uwierzytelniania lokalnie:

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

Następnie, jeśli potrzebuję wywołać Ajax do metody interfejsu API sieci Web, która ma tag [Authorize], po prostu dodaję następujący nagłówek do mojego wywołania Ajax:

{ "Authorization": "Bearer " + window.authenticationToken }
ProfNimrod
źródło
Skąd się response.access_tokenbierze. Czy ustawiasz go z kodu C # ..?
shashwat
Obiekt „response” jest zwracany metodą „token”.
ProfNimrod,
Nie patrzyłem na role. To podejście daje tylko token dostępu, dzięki czemu można wywoływać metody WebApi ozdobione znacznikiem [Authorize]. Przypuszczalnie, gdy wywołasz którąkolwiek z tych metod, możesz sprawdzić role. stackoverflow.com/questions/19689570/mvc-5-check-user-role może pomóc.
ProfNimrod,
A gdzie w tym rozwiązaniu faktycznie uwierzytelniasz swojego użytkownika?
Craig Brett
Punkt końcowy / token jest tworzony automatycznie dla każdego nowego projektu interfejsu API sieci Web. Kod stojący za tym to miejsce, w którym użytkownik jest uwierzytelniany. Jest to nieco bardziej skomplikowane, jeśli dodano kontroler interfejsu API sieci Web do istniejącego projektu MVC.
ProfNimrod