Spring - autentykacja.

0

Załóżmy sytuację, gdy użytkownik chce sprawdzić, czy istnieje użytkownik o podanym username i password (mam to opakowane w klasę LoginForm). Jak dać użytkownikowi możliwość sprawdzenia, czy dane są poprawne? Próbowałem to zrobić przy pomocy Get wraz z RequestBody LoginForm, ale w chwili gdy napotkałem problemy w postmanie (nie mogłem dodać RequestBody do metody Get) przeczytałem, że Get nie powinien przyjmować RequestBody. Więc jak dać użytkownikowi taką możliwość? Czy Spring Security mi w tym pomoże?

Drugie pytanie: Chciałem uniknąć tworzenia sesji z użytkownikami, gdzie w zmiennych sesyjnych przechowywałbym np zalogowanego Usera, więc wpadłem na pomysł, żeby podczas wywoływania "każdej" (każdy wymagający potwierdzenia, że Użytkownik rzeczywiście może np. dodać ofertę) z metod UserControllera musi być podany formularz z loginem czyli metody mniej-więcej wyglądają tak:

 @PostMapping("/order")
    public ResponseEntity addOrder(@RequestBody LoginForm loginForm, @RequestBody OrderDTO orderDTO){
    //jeżeli w bazie danych znajdzie się użytkownik o podanym Username i Password (pola LoginForm) to OrderDTO zostanie zmapowane do Order i wykonana pozostała część metody
    }

Czy jest to poprawne?

Trzecie pytanie: Jak zabezpieczyć system, przed "wykonywaniem' metody sprawdzającej poprawność username i password? Zdaję sobie z tego sprawę, że wysyłając tylko taki Request dostaje się w bardzo krótkim czasie odpowiedź, czy hasło i nick są poprawne, więc można byłoby najpierw sprawdzić czyjś nick, a następnie metodą prób i błędów losować hasła do czasu aż nie dostanie się statusu 200.

0

@AnyKtokolwiek oglądnąłem i po obejrzeniu, skłaniam się ku zrezygnowaniu z LoginForm (czy generowania jakiegoś Tokena) na rzecz ustanowienia sesji z użytkownikiem (za względu, że jest badziej bezpieczna) i przechowywania w jakiejś klasie (np UserSession) Optionala z zalogowanym Userem i w zależności czy uderzając pod endpoint (z metodą PUT) odpowiedzialny za logowanie (zapisanie do Optionala konkretnego Usera) tylko zastanawiam się czy, w tym przypadku, sesja nie okazałaby się zbyt ciężka (mimo, że jest to projekt tylko na githuba + może na pracę inżynierską).

Tylko to rozwiązuje problem z drugim pytaniem, tzn dostałem odpowiedź że jest to poprawne tylko zamiast LoginForm jakiegoś Tokena bym musiał przekazać. Na pytanie trzecie też pobieżnie była odpowiedź w podanym filmie, żeby ustalić delay 200ms. Tylko jak to ustawić? Czy ustawienie tego to ustawienie odpowiednio serwera (np Tomcata czy Ratpacka) czy ustawienie jakiegoś delaya w kodzie klas? Tzn np w kontrolerach?

I dalej pytanie pierwsze, jeżeli bym chciał wygenerować Tokena na podstawie username i password, to i tak musiałbym wysłać RequestBody z username + password. W sumie myślałem, żeby użyć metody Get i po prostu z RequestBody to podać, ale jak teraz myślę sobie łatwiej (i poprawnie) byłoby użyć metody Post i wygenerować Tokena, którym użytkownik by się posługiwał. Dobrze kombinuję?

Który ze sposobów jest częściej spotykany na produkcji? Tworzenie stanowych sesji w bezstanowej Restowej architekturze (czyli po trochu odejście od Resta) czy Tokeny? Sesja ma rację bytu, tak jak w materiale wykładowca mówił, tylko w przypadku gdy będą one lekkie, ale ciężko przewidzieć czy sesje rzeczywiście będą lekkie.

0

Cóż to za ciekawy przypadek użycia: Jak dać użytkownikowi możliwość sprawdzenia, czy dane (jego nazwa użytkownika i hasło) są poprawne? Jaki to ma sens?

0

Teraz zdałem sobie sprawę, po obejrzeniu tego co polecił AnyKtokolwiek, że mój sposób był błędny, bo zakładałem że wraz z każdym uderzeniem pod endpoint, prosiłbym a podanie Loginu i hasła. Wtedy, rzeczywiście musiałbym pozwolić sprawdzić użytkownikowi czy istnieje użytkownik o podanym loginie i haśle (lepiej, żeby użytkownik mógł sprawdzić czy użytkownik podał poprawny login i hasło niż żeby wyszło to przy np dodawaniu oferty), a po stronie klienta wymuszałoby to wysyłanie za każdym razem tych wartości.
Głupi pomysł. Teraz, wydaje mi się że lepiej byłoby zrobić endpoint (login czy jakoś tak) pod który użytkownik by wysyłał login i hasło i w zależności od tego, czy są poprawne zostanie wygenerowany token, którego będę używał do uwierzytelniania (np wyszukiwania Usera któremu odpowiada dany token).

0
Aisekai napisał(a):

Teraz zdałem sobie sprawę, po obejrzeniu tego co polecił AnyKtokolwiek, że mój sposób był błędny, bo zakładałem że wraz z każdym uderzeniem pod endpoint, prosiłbym a podanie Loginu i hasła. Wtedy, rzeczywiście musiałbym pozwolić sprawdzić użytkownikowi czy istnieje użytkownik o podanym loginie i haśle (lepiej, żeby użytkownik mógł sprawdzić czy użytkownik podał poprawny login i hasło niż żeby wyszło to przy np dodawaniu oferty), a po stronie klienta wymuszałoby to wysyłanie za każdym razem tych wartości.
Głupi pomysł. Teraz, wydaje mi się że lepiej byłoby zrobić endpoint (login czy jakoś tak) pod który użytkownik by wysyłał login i hasło i w zależności od tego, czy są poprawne zostanie wygenerowany token, którego będę używał do uwierzytelniania (np wyszukiwania Usera któremu odpowiada dany token).

wiem, że mikrousługi są modne. Bazą do Twojej decyzji jest odpowiedź, czy to jest monolit - choćby monolit udostępniający liczne endpointy REST - czy rozproszenie. W monolicie masz dobrą starą sesję, w rozproszonym nie ma lepszego (chyba) jak JWT. Faktem jest, że w ślicznym modelu bezstanowego REST autentykacja jest jak wrzód ze stanem, ale takie jest życie.

0

@Aisekai, używasz słowa użytkownik do określenia 2 różnych rzeczy. Zrozumienie tego wymaga dużej empatii :)

Klient nie powinien dostawać hasła użytkownika. Hasło użytkownika powinno lecieć prosto do serwisu autoryzacyjnego. Klient może to zrobić przy użyciu Oauth2. Dobrze to jest opisane w introduction w oauth2 rfc: RFC 6749 Introduction. To jest generalna zasada, w Twoim przypadku może rzeczywiście da się to uprościć. Z drugiej strony powszechność obsługi Oauth2 jest tak duża, że może nie warto samemu projektować koła.

Fajną rzeczą jest keycloak, który bierze na siebie całą odpowiedzialność za authentication i authorization. Taka biblioteka do udostępniania uprawnień i zarządzania nimi. Można w niej robić bazę użytkowników, multum możliwości. Instalacja jest banalna - odzipować i odpalić bata.

0

Masz rację, jarekczek, rzeczywiście postaram się o bardziej konkretnie pisać o co mi chodzi, w chwili gdy używam słów wieloznacznych. Mówiąc o kliencie miałem na myśli aplikację będącą interfejsem użytkownika. Z użytkownikiem, chodziło mi o to, że użytkownik (osoba) przez swój interfejs graficzny (klienta) najpierw by sprawdzał czy username i password (pola klasy User) są poprawne, żeby miał pewność że są, ale i tak uderzając pod jakieś endpointy i tak wymagał znów podania username i password jako RequestBody (na podstawie tego, by został wyszukany odpowiedni obiekt klasy User w bazie danych i np dodana do niego oferta). Potem dowiedziałem się o tokenie i rzeczywiście zrodził mi się pomysł, żeby go wykorzystać na zasadzie oddzielnego serwisu. Hasło nigdzie nie wypływa ze strony serwera, dto są pozbawione tego pola, a w bazie danych przechowuję hashowane za pomocą BCrypt (na potrzeby projektu wystarcza)

O ile dobrze zrozumiałem czym są monolity i różnicę między nimi a mikroserwisami, to raczej skupiam się na monolicie ze względu na to, że jest to projekt do portfolio i w przyszłości aplikacja (czy też system) nie będzie rozwijany, na tyle by wymagał przejścia na mikroserwisy. Chyba skłonię się ku utworzeniu sesji choćby ze względu bezpieczeństwa.

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