Dzisiejsza lekcja będzie podzielona na dwie części, w których powiemy sobie o zabezpieczaniu aplikacji z użyciem Spring Security.
W tej lekcji omówimy kilka mechanizmów i pojęć, niezbędnych do zrozumienia zagadnień związanych z zabezpieczaniem aplikacji. W drugiej części dodamy pewne ograniczenia do naszej aplikacji.
Lekcja
Sesja, ciasteczka itp — czyli jak to działa
Protokół HTTP (bezstanowy)
Protokół HTTP jest protokołem bezstanowym, tzn. dwa zapytania do serwera od jednego klienta (przeglądarki/użytkownika) jedno po drugim nie są w żaden sposób ze sobą ‘powiązane’ — tj. serwer nie jest w stanie określić, czy pochodzą od tego samego użytkownika czy nie (mogą być np. z 2 urządzeń, które działają w tej samej sieci, np. w jednym biurze).
Aby temu zaradzić, stworzony został pewien mechanizm, tzw. cookies — cookies to małe pliki, które mogą przechowywać proste informacje (klucz-wartość), dostępne tylko dla danej strony internetowej (np. inna strona internetowa nie jest w stanie odczytać ciasteczek Twojej aplikacji webowej — ma to na celu zwiększenie bezpieczeństwa, choć czasem zdarza się, że w przeglądarkach internetowych są pewne luki). Ciasteczka z kolei są wykorzystywane do obsługi mechanizmu sesji poprzez zapisanie w ciasteczku tzw. identyfikatora sesji — unikalnego ciągu znaków, który w połączeniu z adresem IP pozwala jednoznacznie zidentyfikować użytkownika strony i powiązać go z zapytaniami, które wykonuje na serwerze.
Sesja i obsługa w Springu
Sesje działają trochę podobnie jak wspomniane ciasteczka — pozwalają przechowywać pary klucz-wartość unikalne dla danego użytkownika. Mówiąc w kontekście języka Java, można je porównać do obiektu typu Map<String, Object>, który jest unikalny dla każdego fizycznego użytkownika. Różnica pomiędzy sesją a ciasteczkiem jest taka, że o ile ciasteczka są przechowywane po stronie klienta (np. w przegladarce), sesja jest przechowywana na serwerze (użytkownik nie ma więc możliwości manipulowania nią bezpośrednio), jest też bardziej elastyczna (ciasteczka pozwalają przechowywać pary klucz-wartość, gdzie zarówno klucz jak i wartość to ciąg znaków, w przypadku sesji wartość może być dowolnym obiektem).
W Springu z sesji możemy korzystać bezpośrednio — np. dodając jako argument naszej metody w kontrolerze obiekt typu HttpSession, np w ten sposób:
@Controller
public class Kontroler {
@RequestMapping(“/”)
public String zrobCos(HttpSession session) {
//...
}
}
Drugi sposób to korzystanie z sesji nie wprost — np. używając biblioteki opartej o mechanizm sesji (np. Spring Security, o którym dzisiaj będziemy rozmawiać) lub tworząc beany o tzw. zasięgu sesyjnym.
Zasięg sesyjny
Pojęcie zasięgu
W springu istnieje pojęcie zasięgu danego beana (komponentu). Oznacza on, w jakim kontekście jest on ‘unikalny’ — domyślny zasięg to singleton, co oznacza, że w całej aplikacji mamy tylko jeden taki obiekt. W naszej aplikacji jednak często jest potrzeba utworzenia komponentu, który będzie powiązany z użytkownikiem i widoczny tylko w jego ‘kontekście’. Do tego właśnie możemy użyć zasięgu sesyjnego.
Zasięgi w Spring’u
Aby ustawić konkretnemu beanowi (np. serwisowi lub dao jeśli jest taka potrzeba) odpowiedni zasięg, używamy adnotacji @Scope( zasieg ), gdzie zasieg to jeden z poniższych:
- ConfigurableBeanFactory.SCOPE_SINGLETON — domyślna wartość, jest tylko jeden obiekt tego typu w całej aplikacji
- ConfigurableBeanFactory.SCOPE_PROTOTYPE — za każdym razem, kiedy ten bean jest używany, tworzony jest nowy obiekt (ale uwaga, ‘używany’ tzn np. podłączany przy użyciu adnotacji @Autowired do innego beana, a nie za każdym razem, kiedy korzystamy z jego metod; innymi słowy, za każdym razem, kiedy pobierany jest on z kontekstu Spring’a)
- WebApplicationContext.SCOPE_REQUEST — tworzony jest osobny obiekt do obsługi każdego osobnego zapytania HTTP (czyli przy wyświetleniu każdej strony)
- WebApplicationContext.SCOPE_SESSION — tworzony jest dla każdej sesji, czyli najczęściej dla każdego jednego użytkownika korzystającego z aplikacji w danym momencie
Zasięg sesyjny
Zasięg sesyjny jest dla nas najbardziej interesujący na ten moment i na nim się skupimy. W praktyce do tej pory nie miałem okazji korzystać za często z innych zakresów poza sesyjnym, były to dość specyficzne przypadki i wydaje mi się, że na początku swojej kariery raczej nie spotkasz się z podobną sytuacją :)
Beana w zasięgu sesyjnym możemy utworzyć np. w celu przechowywania danych użytkownika w wygodniejszej formie (Spring Security oferuje taką możliwość, ale korzystanie z tego obiektu może być dość problematyczne). Co ważne, sesja (a więc także beany o takim zasięgu nie są tworzone w momencie zalogowania, a w momencie pierwszego zapytania HTTP do naszej aplikacji (np. wejścia na stronę główną)! Dlatego ważne jest, aby w beanach tego typu uwzględniać także możliwość, że użytkownik nie jest zalogowany.
Spring security
Spring Security to biblioteka rozwijana wraz z frameworkiem (choć może być używana niezależnie od niego), która pozwala na bardzo elastyczną konfigurację za pomocą bardzo małej ilości kodu (właściwie to XMLa).
Główny koncept Spring Security opiera się o filtry, czyli każde zapytanie przechodzi przez zestaw ‘kryteriów’ z których każde może zdecydować o tym, czy odmówić dostępu, udzielić go, lub przekazać decyzję dalej. W połączeniu z bardzo szeroką gamą gotowych komponentów i konfiguracji możemy szybko i sprawnie umożliwić np. logowanie za pomocą Facebooka czy też zwykłego loginu i hasła.
Spring Security obejmuje dwa zagadnienia — uwierzytelnianie i autoryzację. Pierwszy z nich, to innymi słowy potwierdzenie, że ktoś jest osobą za którą się podaje. Może to być w formie podania loginu i hasła, zalogowania przez Facebook czy Google+ itp. Drugie, to określenie, czy zalogowany (uwierzytelniony) użytkownik ma prawo wykonać daną czynność (pokazać szczegóły elementu, usunąć element itp).
Spring Security pozwala na bardzo precyzyjne i wygodne zarządzanie bezpieczeństwem aplikacji — możemy przede wszystkim określić reguły dla całych wzorców URL (np. powiedzieć, że poza stroną logowania osoby niezalogowane nie mogą nic wyświetlić) ale też dla pojedynczych metod (czyli np. ta strona może być wyświetlona tylko administratorom). Tymi dwoma sposobami będziemy się zajmowali w drugiej części tej lekcji. Warto jednak wiedzieć, że Spring Security może też więcej — np. z kolekcji obiektów zwracanej z jakiejś metody usunąć te, do których użytkownik nie ma uprawnień lub sprawdzić, czy wywołanie metody jest możliwe przez użytkownika akurat dla podanych argumentów!
O samym Spring Security można by napisać naprawdę sporo i sporo już zostało napisane — dla osób ciekawych (a także dla tych, które chcą/potrzebują zrozumieć zasadę działania lub zmodyfikować coś) gorąco polecam książkę Pro Spring Security autorstwa Carlo Scarioni
Jeśli uważasz powyższą lekcję za przydatną, mamy małą prośbę: polub nasz fanpage. Dzięki temu będziesz zawsze na bieżąco z nowymi treściami na blogu ( i oczywiście, z nowymi częściami kursu Javy). Dzięki!