Logowanie i utrzymanie sesji w angularze, autoryzacja przy requestach na podstawie konta

0

Witam, tworze aplikacje webową opartą o angular i .net core, aplikacja ma zwracać pewne dane oraz pozwalać na ich dodawanie, jednak dodawać można tylko w przypadku zalogowania się na konto. Mam już gotowe api dodające i zwracające żądane dane, jednak póki co nie ma tam żadnej autoryzacji. Mój problem polega na tym że bardzo mało wiem o działaniu angulara przez co nie wiem jak wykonać autoryzacje. Aplikacja ma działać tak:

  • dane mogą pobierać wszyscy
  • dodawać wpisy mogą tylko zalogowani
  • edytować wpisy mogą tylko ich twórcy
    Moje pytanie brzmi następująco. Jak stworzyć autoryzacje, a raczej jak ma działać autoryzacja w funkcjach dodających i edytujących tak żebym potem w angularze mógł wykorzystać ją do logowania użytkowników i utrzymywania ich zalogowanych?
    Jednocześnie byłbym bardzo wdzięczny za nakierowanie na to czego mam poszukać, tak żeby wyjaśniło mi ten proces po stronie angulara.
    Z góry bardzo dziękuje.
1

JSON Web Tokens to Twoje hasło na dziś :)

0
Veox napisał(a):

JSON Web Tokens to Twoje hasło na dziś :)

Troszeczkę już czytałem o JWT, tylko nie wiem jak wygląda cały proces jeżeli chodzi o logowanie użytkownika.
Generalnie użytkownik wysyła nam login i hasło, sprawdzamy w bazie czy mamy taki wpis, jeżeli mamy to zwracamy token generowany przez algorytmy JWT który jest ważny, 15 minut, 30, albo 8h, jak już tam sobie ustawimy.
I rozumiem że to się sprawdza przy synchronizacji systemów pomiędzy firmami, jedna generuje konto dla drugiej, i jak ta druga chce skorzystać z api pierwszej to przy wysyłaniu request'a przechodzi autoryzację, to jest dla mnie jasne.
Co jednak kiedy w grę wchodzi logowanie? Czy token który dostajemy raz jest cały czas przechowywany w sesji do jego wygaśnięcia? Czy w back-endzie powinniśmy go chwilowo przypisywać do danego użytkownika w bazie danych? I ostatecznie jak działa autoryzacja? Czy token jest przesyłany za każdym razem do funkcji które jego wymagają i na jego podstawie znajduję się konto na jakim się aktualnie działa?

Wiem że to sporo pytań ale też temat wydaje mi się skomplikowany i dość poważny więc wole nie zostawiać sobie miejsca na niepewność.

1
krystianknowak napisał(a):

Co jednak kiedy w grę wchodzi logowanie?

to nie ma żadnego problemu.

krystianknowak napisał(a):

Czy token który dostajemy raz jest cały czas przechowywany w sesji do jego wygaśnięcia?
Czy w back-endzie powinniśmy go chwilowo przypisywać do danego użytkownika w bazie danych?

Wygenerowany token jest przechowany po stronie użytkownika, w ciasteczku czy też localstorage, na serwerze token nie jest przechowywany.

krystianknowak napisał(a):

I ostatecznie jak działa autoryzacja? Czy token jest przesyłany za każdym razem do funkcji które jego wymagają i na jego podstawie znajduję się konto na jakim się aktualnie działa?

Tak, token dołącza się do każdego requesta wymagającego autoryzacji. I wtedy z tokena możesz bardzo prosto uzyskać zawarte w nim claimsy:

var identity = HttpContext.User.Identity as ClaimsIdentity;
var userGuid = new Guid(identity.Claims.FirstOrDefault(x => x.Type == "uGuid").Value);
var userMail = identity.Claims.FirstOrDefault(x => x.Type == "uMail").Value;

Tutaj masz ładnie to opisane od strony web api w net core 2.x:
https://auth0.com/blog/securing-asp-dot-net-core-2-applications-with-jwts/

0

To już chyba wszystko co chciałem wiedzieć, ogromnie dziękuje za odpowiedź, zabieram się do roboty :)

5

Logując się na nowej maszynie otrzymujesz token oraz refresh token (o tym za chwilę). Zatem każde nowe urządzenie powinno mieć taką parę kluczy, którą będzie przechowywać w pamięci. Token przechowujemy w pamięci tymczasowej (zmienna), natomiast refresh token w pamięci stałej (cookie lub local storage).

Token powinien mieć jak najkrótszy czas ważności. Jego czas zależy od częstotliwości żądań do serwera. Zazwyczaj czas waha się w okolicach 5-15 minut. Jest to średni czas korzystania z appki (w sensie częste requesty).

Refresh token służy nam do odświeżenia tokena głównego po jego wygaśnięciu (taka a'la sesja). Dzięki temu zabiegowi użytkownik nie musi się logować co 15 minut. Przed wysłaniem żądania sprawadzamy ważność tokena głównego. Jeśli jego czas ważności wygasł, prosimy serwer o przyznanie nowego tokena używając refresh token. Następnie wykorzystując świeży token wykonujemy żądanie.

Refresh token powinien być przechowywany w bazie danych w postaci refresh-token (+ np. jakaś nazwa urządzenia do wyświetlenia aktywnych sesji) + user id. Dzięki temu możemy generować nowe tokeny dla danego użytkownika na danej maszynie bez konieczności ponownego logowania. Usuwając refresh token z bazy, usuwamy aktywną sesję na danym urządzeniu i wymagane będzie ponowne logowanie. Skoro jesteśmy przy tym temacie, to przy ponownym uruchomieniu aplikacji (za dzień, dwa itp.) wysyłamy żądanie o token wykorzysując refresh-token. Jeśli widnieje on w bazie, to zostaniemy zalogowani. Kiedy z innego urządzenia usuniemy sesję, to wymagana będzie ponowna autentykacja.

Autoryzacja działa na podstawie nagłówków HTTP. JWT Token przechowuje informacje o użytkowniku, więc w momencie wysłania żądania, odczytujemy tę wartość z nagłówka HTTP. Czyli nie dołączasz w body informacji o tokenie. Jest ona w nagłówku. Jest to istotne, ponieważ tylko POST i PUT posiadają body. GET oraz DELETE już nie.

W części webowej aplikacji dołączasz nagłówek:

fetch('api_url', {
    method: 'get',
    headers: new Headers({
        'Authorization': `Bearer ${JWTToken}`
    })
});

W części serwerowej odbierasz go:

if(req.headers.authorization) {
    const tokenType = req.headers.authorization.split(' ')[0];
    const token = req.headers.authorization.split(' ')[1];
    
    // Sprawdzanie czy token jest ważny
    
    let user = undefined;

    if(tokenType === 'Bearer') {
        // Odczytujemy dane z Bearer token i przypisujemy je do user
    } else {
        // Odczytujemy dane z innego tokena i przypisujemy je do user
    }
    
    if(user) {
        // Użytkownik jest zautoryzowany, mamy dostęp np. przez
        const userId = user.id;
    }

}

Dzięki temu wyślesz nagłówek wraz z żądaniem, a serwer będzie w stanie je autoryzować. Jest to zachowanie opcjonalne, możesz autoryzować tylko określone endpoints, lecz zawsze wysyłaj token (nie wiesz kiedy się przyda ;)).

Okej, a co w przypadku zamknięcia sesji w czasie kiedy token jest jeszcze aktywny? Otóż można wrzucić dany token do czarnej listy w bazie danych aplikacji, aby nikt więcej nie mógł go użyć. To dodaje nam kolejną walidację (chociaż uważam, że równie dobrym rozwiązaniem jest trzymanie czarnej listy w pamięci aplikacji i czyszczenie jej co pewien interwał czasu).

Ufff, sporo tego wyszło, ale mam nadzieję, że to rozwieje trochę Twoje wątpliwości ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1