Auth0 – Aplikacja do odpalania rakiet – backend

Kontrola dostępu

Niestety w obecnej postaci dowolna osoba w internecie jest w stanie anonimowo wywołać metody naszego serwisu.

Aby włączyć obsługę kontroli dostępu należy do metod Configure i ConfigureServices klasy Startup dodać następujący kod:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddAuthentication();
    services
        .AddAuthorization();
    services
        .AddMvc()
        .AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseAuthentication();
    app.UseMvc();
}

Metody AddAuthentication i UseAuthentication – sprawiają, że aplikacja wspiera autentykację – czyli będzie próbować zidentyfikować użytkownika który się łączy z aplikacją. Bez identyfikacji użytkownika weryfikowanie kontrola dostępu jest niemożliwa, czasami jednak identyfikowanie użytkownika bez kontroli dostępu ma sens (np. w celach statystycznych).

Metoda AddAuthorization – sprawia, że aplikacja wspiera autoryzację czyli kontrolę dostępu.

Framework Mvc umożliwia selektywne włączenie kontroli dostępu, domyślnie wszystkie akcje wszystkich kontrolerów są dostępne publicznie. Aby ograniczyć dostęp tylko dla zalogowanych użytkowników należy dodać wpis:

using Microsoft.AspNetCore.Authorization;

w sekcji using kontrolera oraz linijkę [Authorize] nad metodą kontrolera:

public class IndexController : Controller
{
    [Authorize]
    [HttpGet]
    [Route("missile-types")]
    public IActionResult GetMissileTypes()
    {
    	...
    }
    ...
}

Atrybut Authorize może też być użyty nad całym kontrolerem sprawi to że wszystkie metody kontrolera będą wymagały kontroli dostępu

[Authorize]
public class IndexController : Controller
{
...
}

Jeżeli wszystkie akcje wszystkich kontrolerów wymagają autoryzacji, można darować sobie dodawanie atrybutu Authorize w każdym z nich i zmodyfikować klasę Startup tak też zrobiłem.

Najpierw dodałem dwa wpisy w sekcji using:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;

oraz zmodyfikowałem użycie metody AddMvc

services.AddMvc(o =>
{
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
    o.Filters.Add(new AuthorizeFilter(policy));
})
.AddJsonOptions(options => options.SerializerSettings.Converters.Add(new StringEnumConverter()));

Linijka „o.Filters.Add” dodaje element do listy „Filtrów”. Filtry to obiekty klas implementujących interfejs IFilterMetada (dużo trudnych słów, dla kogoś, kto zaczyna programować). Filtry mogą być wywoływane przed/po albo zamiast akcji kontrolera i modyfikować wynik akcji, albo dostarczać jej parametrów. Jednym z filtrów jest AuthorizeFilter, który działa podobnie jak dodanie atrybutu Authorize. Jako parametr konstruktora akceptuje on politykę. Politykę da się stworzyć przy pomocy metody build klasy AuthorizationPolicyBuilder, może on być bardzo rozbudowana jednak w naszym przypadku, wymagamy tylko aby nie dało się dokonywać anonimowych wywołań metod, użyłem więc metody RequireAuthenticatedUser.

Próba pobrania listy typów pocisków na tym etapie rozwoju aplikacji powoduje wystąpienie błędu:

Błąd wynika z faktu iż istnieje wiele różnych metod identyfikacji użytkownika, a nasz kod nie wskazuje, która ma być wykorzystana.

Większość z metod opiera się na nagłówku Authorize wywołania. Przeglądarki nie pozwalają użytkownikom łatwo dodawać nagłówków, jednak bardzo łatwo da się to zrobić z kodu aplikacji. W większości technologii wygląda to mniej więcej tak:

request.headers.add('Header', 'Header-content')

Nagłówek Authorize składa się z dwóch elementów: typu poświadczeń i samych poświadczeń oddzielonych spacją. Najprostszym typem jest Basic. Polega on na rozdzieleniu loginu i hasła dwukropkiem i zakodowaniu w base64. Np. autoryzacja użytkownika o loginie admin i haśle „kopytko” wygląda następująco:

request.headers.add('Authorize', 'Basic YWRtaW46a29weXRrbw==')

Autoryzacja typu Basic ma jednak wiele wad min. fakt iż login i hasło są przesyłane na prawo i lewo, co może prowadzić do wycieku.

Współcześnie powszechnie wykorzystywana jest metoda JWT (Json Web Tokens). Aby wskazać, że aplikacja używa do autoryzacji JWT jako typ autoryzacji należy podać 'Bearer’, poświadczenia – token składa się z trzech sekcji rozdzielonych kropkami. Pierwsza sekcja to nagłówek – dokument json zakodowany w base64 zawierający dane techniczne. Druga sekcja to także dokument json zakodowany w base64, zawiera on dane związane z kontrolą dostępu, często zawiera on dane użytkownika jego nazwę, email, przypisane role czy zakres uprawnień, powinien też zawierać takie dane jak: adresat (aud – audience) – serwis na potrzeby, którego token został wystawiony – inne serwisy powinny odrzucać token nie adresowany do nich, wystawcę (aut – authority), termin wygaśnięcia (exp – expiry) – termin po którym token nie powinien być akceptowany, klejmsy (claims) – słowo nie dające się łatwo przetłumaczyć – są to inne dane związane z użytkownikiem lub sesją – najłatwiej jest je zrozumieć na przykładzie facebooka – Aplikacja korzystająca z API facebooka może działać w imieniu użytkownika – np. udostępniać coś na jego tablicy. Aby to było możliwe aplikacja musi posiadać token, gdyby nie było pola claims token umożliwiałby aplikacji robiebie z kontem co by chciała, np. analizowę prywatne wiadomości. W polu claims może znajdować się zakres uprawnień aplikacji, która prosząc o token musi ten zakres podać, użytkownik ma do nich wgląd i może je zakaceptwać. Aplikacja może z tym tokenem dodawać wpisy na ścianie, jednak gdy spróbuje połączyć się z serwisem wiadomości prywatnych, zostanie grzecznie ale stanowczo spuszczona na drzewo.

Ostatnią częścią tokenu jest podpis cyfrowy zakodowany w base64, gwarantujący, że reszta tokenu nie była modyfikowana od momentu wystawienia.

Obsługa identyfikacji przy pomocy Tokenów jest dobrze wspierana w .net. Aby ją dodać należy dodać wpis w sekcji using klasy Startup

using Microsoft.AspNetCore.Authentication.JwtBearer;

oraz zmodyfikować użycie metody AddAuthentication.

services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.Authority = "";
        options.Audience = "";
    });

Właściwości options.DefaultAuthenticateScheme options.DefaultChallengeScheme określają typ autoryzacji jakiego oczekuje aplikacja, JwtBearerDefaults.AuthenticationScheme ma wartość „Bearer”.

Metoda AddJwtBearer określa szczegóły weryfikacji tokenu, dwa podstawowe parametry to Authority – akceptowany wystawca tokenu i Audience – identyfikator serwisu znany przez wystawcę. Aby uzupełnić te pola należy zarejestrować ten serwis – API.

2 odpowiedzi do “Auth0 – Aplikacja do odpalania rakiet – backend”

  1. Pingback: dotnetomaniak.pl

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *