Spring Boot, AngularJS, Spring Security

Spring Boot, AngularJS, Spring Security
NA
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:68
0

Cześć.
// tl;dr -> patrz tylko 2.
1. Zamierzam stworzyć web aplikację z wykorzystaniem Springa i AngularaJS. Od jakiegoś czasu kombinuję z jedną i drugą technologią testując jak działają różne rzeczy. Niedawno udało mi się wreszcie skonsumować resta, po tym jak doczytałem, że aplikację po stronie klienta wystarczy wrzucić do folderu webapp, gdzie spring boot domyślnie szuka pliku index.html (wiem, że można rozdzielić serwer z klientem (bodajże jakieś CORSy), ale dopiero uczę się tych technologii i naprawdę chcę przejść po linii najmniejszego oporu, systematycznie uzupełniając wiedzę, bo już nie raz się zaciąłem, chcą zrobić wszystko na raz). Aplikacja będzie wymagała utworzenia konta użytkownika (nawet bez maila, wystarczy username i password) i zalogowania się.
Googlowałem już na różny sposób tagi 'spring boot angularjs security' i znalazłem masę informacji (może aż za dużo?), w tym tutorial na stronie spring.io, ale albo instrukcje są dość chaotyczne, albo mało wyjaśniają, ewentualnie są niepełne, a czasem próbują zrobić wszystko na raz (autoryzacja w przypadku rozdzielenia modułu, jakaś własna baza tokenów itp itd), kiedy ja potrzebuję czegoś najprostszego, od czego mógłbym zacząć, dlatego zdecydowałem się (narażając na opinię człowieka, który nie umie szukać/korzystać z informacji z googla) poprosić o pomoc na 4p.

-----------------

2. Chciałbym się dowiedzieć, co mi będzie niezbędne do nauczenia się, poczytania w dokumentacji (może znacie jakieś konkretne linki albo już mieliście taki problem?), aby:

  • a) zabezpieczyć resty, a dokładnie, że dostęp do konkretnych ścieżek mogą mieć tylko użytkownicy z rolą USER / ADMIN / KTOŚ_TAM;

  • b) zrobić stronę logowania w Angularze (i umożliwyć wylogowanie się);

  • c) zrobić stronę rejestracji nowego użytkownika w Angularze i zapisać tego usera do bazy danych (z samą bazą umiem się połączyć);

  • d) móc przechowywać aktualnie zalogowanego użytkownika (żeby jak ten kliknie 'moje konto' to wyświetliły się dane właśnie z jego danymi; jakiś user_context czy coś);

O ile na 'a' znalazłem całkiem niemało informacji w necie, o tyle na 'b' już mniej, a na 'c' czy 'd' - w ogóle (przynajmniej opisanych w jakiś przystępny dla laika sposób).
Jak wspominałem, pragnę poznać najprostszy sposób. Co do 'c' to rozumiem, że wystarczy encja z nazwą użytkownika, hasłem i... no właśnie rolą czy rolami? W sensie jak ktoś jest adminem to automatycznie ma też w sobie rolę 'USER'? Muszę trzymać dwie role? Czy zaznaczyć w konfiguracji security, że dane ścieżki są dostępne dla 'USER' i 'ADMIN'? Jeśli tak, to pole 'role' powinno się trzymać jako String czy Enum?

-----------------

3. Przy okazji ciekawi mnie kilka rzeczy (jeśli ktoś jest w stanie odpowiedź w 2-3 zdaniach, przedstawić esencję problemu, zamiast odsyłać do kilkudziestu stron dokumentacji :)):

  • a) Jak to jest zrobione, że dwie oddzielne rzeczy (jakimi są serwis restowy i część po stronie klienta) są w stanie dbać o autoryzację?

  • b) Skąd serwer wie, że właśnie dany użytkownik jest właśnie zalogowany? Chodzi mi o to, że angular może rzucić GET na jakąś ścieżkę a serwer ma zwrócić np. jakiegoś JSONa, ale skąd wie, że to żądanie przyszło właśnie od takiego użytkownika z danymi uprawnieniami (skoro jak zdążyliśmy ustalić, te rzeczy są odrębne)?

  • c) I jak to jest, ze np. jak wyłączymy stronę i nie wrócimy na nią po chwili, to zostajemy wylogowani? Spring liczy jakoś czas 'nieaktywności' dla każdego zalogowanego użytkownika i np. po 'x' takich minutach automatycznie wylogowuje (chyba że zaznaczymy coś w rodzaju 'rememeber me')?
    Po prostu chciałbym też nieco zrozumieć, a nie tylko bezmyślnie przepisywać kod.

Bardzo proszę o pomoc, chciałbym to zrozumieć i się tego nauczyć.

edytowany 4x, ostatnio: Naitoreivun
0

to bardzo dobre pytania, będę obserwował temat bo też mnie niektóre rzeczy trapiły

S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
1

Jak wspominałem, pragnę poznać najprostszy sposób. Co do 'c' to rozumiem, że wystarczy encja z nazwą użytkownika, hasłem i... no właśnie rolą czy rolami? W sensie jak ktoś jest adminem to automatycznie ma też w sobie rolę 'USER'? Muszę trzymać dwie role? Czy zaznaczyć w konfiguracji security, że dane ścieżki są dostępne dla 'USER' i 'ADMIN'? Jeśli tak, to pole 'role' powinno się trzymać jako String czy Enum?

Tak jak zechcesz

c) zrobić stronę rejestracji nowego użytkownika w Angularze i zapisać tego usera do bazy danych (z samą bazą umiem się połączyć);

Wysyłasz POSTa z danymi i tworzysz encje. Tylko pamiętaj użyć password Encodera po drodze :)


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
edytowany 1x, ostatnio: scibi92
MC
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 7 godzin
  • Postów:4
1

a) zabezpieczyć resty, a dokładnie, że dostęp do konkretnych ścieżek mogą mieć tylko użytkownicy z rolą USER / ADMIN / KTOŚ_TAM;

Cały temat autoryzacji i autentykacji możesz oprzeć na sesji albo na tokenie. Osobiście w przypadku o którym piszesz wole użycie tokenów. Podczas logowania użytkownika wysyłasz do części backendowej POST z loginem i hasłem użytkownika. Tam sprawdzasz czy dane do autoryzacji się zgadzają i generujesz i odsylasz token w którym zapisujesz informacje potrzebne do autoryzacji (mozesz umiescic tam wszystko co tylko bedzie Ci potrzebne w komunikacji miedzy angularem a springiem). Token ten później przesyłasz w headerze każdego zapytania REST'owego, dzieki czemu spring wie czy i jakie treści może zaserwować. Podczas generacji ustawiasz także czas ważności takiego tokena (później możesz ten token odświeżać).

b) zrobić stronę logowania w Angularze (i umożliwyć wylogowanie się);

Strona logowania formularz z loginem i haslem przesylany POST'em z prosba o token. W momencie wylogowania po prostu niszczysz token w angularze i przekierowywujesz na strone logowania, to wszystko.

c) zrobić stronę rejestracji nowego użytkownika w Angularze i zapisać tego usera do bazy danych (z samą bazą umiem się połączyć);

Strone rejstracji robisz w taki sam sposób jak stronę logowania. Przesyłasz dane do założenia użytkownika do springa POST'em. Spring łączy się z bazą, zakłada użytkownika i zwraca do angulara odpowiednia wiadomość.

d) móc przechowywać aktualnie zalogowanego użytkownika (żeby jak ten kliknie 'moje konto' to wyświetliły się dane właśnie z jego danymi; jakiś user_context czy coś);

Twój user_context możesz śmiało trzymać w tokenie i z niego odczytywać w angularze.

a) Jak to jest zrobione, że dwie oddzielne rzeczy (jakimi są serwis restowy i część po stronie klienta) są w stanie dbać o autoryzację?

b) Skąd serwer wie, że właśnie dany użytkownik jest właśnie zalogowany? Chodzi mi o to, że angular może rzucić GET na jakąś ścieżkę a serwer ma zwrócić np. jakiegoś JSONa, ale skąd wie, że to żądanie przyszło właśnie od takiego użytkownika z danymi uprawnieniami (skoro jak zdążyliśmy ustalić, te rzeczy są odrębne)?

W springu tworzysz sobie odpowiedni filter który przy każdym zapytaniu sprawdza czy przesłano w nagłówku token, waliduje poprawność tokena. Jeśli wszystko się zgadza, to przetwarzasz dalej to zapytanie, jeśli nie, to odsylasz 403. Filtr ten może obejmować tylko konkretne ścieżki (np. strony /login udostepniasz dla wszystkich, ale już dla strony /mojekonto/** filtrujesz wszystkie zapytania).

I jak to jest, ze np. jak wyłączymy stronę i nie wrócimy na nią po chwili, to zostajemy wylogowani? Spring liczy jakoś czas 'nieaktywności' dla każdego zalogowanego użytkownika i np. po 'x' takich minutach automatycznie wylogowuje (chyba że zaznaczymy coś w rodzaju 'rememeber me')?

Podczas każdorazowej walidacji tokenu sprawdzasz jego czas wygaśnięcia.

Postać takiego tokena możesz sobie sam wymyślić, jednak są przyjęte standardy których warto się trzymać. Polecam JSON Web Tokens (https://jwt.io/) do których bez problemu znajdziesz biblioteki prawie w każdym języku.

0

Token trzymać w bazie tak?
Np. encje User i UserToken z relacją 1:1?
Czy Spring ma jakieś ułatwienia co do tego?
No i każdy request ma być sprawdzany pod kątem praw dostępu, czy Spring to daje z automatu?

MC
  • Rejestracja:prawie 9 lat
  • Ostatnio:około 7 godzin
  • Postów:4
1

Tokena nie musisz trzymać po stronie back-endu, dzięki czemu powiedzmy, że masz zachowaną bezstanowość. W momencie generowania tokena przy logowaniu (ewentualnie przy późniejszym odświeżaniu), podpisujesz go sobie. Nikt Ci go zatem nie zmieni, ani nie podrobi. Jeśli chodzi o ułatwienia to wszystko zrobi za ciebie spring security + jose4j / java-jwt. Każdy request jest sprawdzany pod kątem praw dostępu i robi to za Ciebie spring z automatu w momencie gdy zdefiniujesz sobie filter sprawdzajacy token.

NA
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:68
0

Dziękuję za odpowiedzi.

@scibi92 ->
Chciałbym to ja poznać dobre praktyki :) W sensie są jakieś różnice że lepiej do takich rzeczy Enum albo String?
Rozumiem, że wysyłam POSTa który zawiera username i normalny password, a dopiero po stronie javy w controllerze hashuje go i porównuje z tym co siedzi w bazie danych, o ile odpowiedni username istnieje?


Zakładając że wszystkie resty bedę miał w '/api/**', a strony będą miały jakieś normalne intuicyjne nazwy. Zrobię sobie panel boczny i tam 2 zakładki: 'twoje konto', 'panel admina'. Żeby to drugie było widoczne tylko dla admina, mógłbym użyć ng-If=user.isAdmin() i sprawdzić czy posiada odpowiednią rolę. Ale z tego co wiem, nie ma chyba problemu, żeby ktoś sobie otworzył konsolę i zmienił na ng-If=true. Czy może nie muszę się tym przejmować, póki operacje znajdujące się w panelu admina oraz dane się tam wyświetlające, będą dostępne z restów /api/admin/**, do których user sobie dostępu nie umożliwi z poziomu JSa?

MA
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 3 lata
  • Postów:166
0

Wymienione przez ciebie technologie wykorzystywane są w generatorze kodu JHipster. Możesz sobie wygenerować kod odpowiedzialny za logowanie z wykorzystaniem tokenów (albo zwykłe logowanie sesyjne) i podejrzeć jak to jest zaimplementowane.

NA
Wiem, już tego próbowałem. Ale masa kodu, która się generuje, jest przytłaczająca dla kogoś, kto nie siedzi w temacie. Wolę dojść do tego krok po kroku powoli i zrozumieć, niż uznać "ok, jakoś to działa".
0
Naitoreivun napisał(a):

Dziękuję za odpowiedzi.
Zakładając że wszystkie resty bedę miał w '/api/**', a strony będą miały jakieś normalne intuicyjne nazwy. Zrobię sobie panel boczny i tam 2 zakładki: 'twoje konto', 'panel admina'. Żeby to drugie było widoczne tylko dla admina, mógłbym użyć ng-If=user.isAdmin() i sprawdzić czy posiada odpowiednią rolę. Ale z tego co wiem, nie ma chyba problemu, żeby ktoś sobie otworzył konsolę i zmienił na ng-If=true. Czy może nie muszę się tym przejmować, póki operacje znajdujące się w panelu admina oraz dane się tam wyświetlające, będą dostępne z restów /api/admin/**, do których user sobie dostępu nie umożliwi z poziomu JSa?

Co z tego, że sobie podmieni coś w DOM skoro nic to nie da, bo treści serwuje backend (Java) i ona zadba o to, co moze widziec

S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

W sensie są jakieś różnice że lepiej do takich rzeczy Enum albo String?

Ale gdzie?

Rozumiem, że wysyłam POSTa który zawiera username i normalny password, a dopiero po stronie javy w controllerze hashuje go i porównuje z tym co siedzi w bazie danych, o ile odpowiedni username istnieje?

No tak


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
NA
Bo napisałeś, iż mogę zrobić jak chcę, czyli do roli wybrać albo Enum'a, albo Stringa, ale zastanawiam się, czy są jakieś dobre praktyki, które mówią, że należy wybrać jedno, a wystrzegać się drugiego? I dlaczego.
S9
Oczywiście że role to stringi bo te są przechowywane w bazie danych...
NA
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)