#16.3 — zabezpieczanie aplikacji z użyciem Spring Security

By 1 February 2015 February 6th, 2016 Kurs Javy

W poprzed­nich częś­ci­ach tej lekcji mówiliśmy o samej kon­cepcji Spring Secu­ri­ty oraz o tym, jak skon­fig­urować aplikację, aby z niego korzys­tała. Dzisi­aj dowiemy się, jak wyko­rzys­tać tą kon­fig­u­rację w naszej aplikacji :)

Dzisi­aj trze­cia i ostat­nia część tej lekcji — zobaczymy, jak uży­wać SpringSe­cu­ri­ty w prak­tyce w naszej aplikacji. Po tej lekcji będziesz wiedzi­ała, jak zabez­pieczyć wybrane strony, wyświ­etlić ład­ny for­mu­la­rz logowa­nia i zmieni­ać zachowanie Spring Secu­ri­ty. Prze­jdźmy więc do samej lekcji :)

Lekcja

Konfiguracja własnego formularza logowania

W poprzed­niej lekcji korzys­tal­iśmy z for­mu­la­rza logowa­nia wygen­erowanego przez Springa — dzisi­aj zmien­imy to w taki sposób, aby uży­wać własnego.

Przede wszys­tkim potrze­bu­je­my widoku, który będzie wyświ­et­lał rzec­zony for­mu­la­rz — nie musi to być jak­iś spec­jal­ny widok, inte­grac­ja pole­ga na tym, że wysyłamy odpowied­nio spreparowane dane pod odpowied­ni adres. W tym miejs­cu zakładam, że sama dopa­su­jesz swój szablon — przed­staw­iony przykład może wyglą­dać u Ciebie inaczej, ale real­nie ważne są głównie atry­bu­ty ‘name’ pól oraz ‘action’ całego for­mu­la­rza. Układ wiz­ual­ny, kole­jność pól i style nie mają znaczenia :) Będziemy więc pra­cow­ać na poniższym przykładzie:

<c:set var="loginUrl"><c:url value="/login"/></c:set>
<form method="post" action="${loginUrl}">
    <input type="text" name="email" />
    <input type="password" name="password" />
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
    <input type="submit" value="Zaloguj" />
</form>

Pier­wsza linia ustaw­ia zmi­en­ną EL o nazwie login­Url i wpisu­je do niej wartość — adres URL wygen­erowany dla adresu względ­nego /j_spring_security_check . Trze­cia lin­ij­ka od koń­ca to zabez­piecze­nie przed CSRF — włączymy to zabez­piecze­nie w naszej konfiguracji.

CSRF to jed­na z metod ataku na aplikac­je webowe, który pole­ga na takim przekierowa­niu użytkown­i­ka (w sposób niewidoczny), żeby wykon­ał bez świado­moś­ci pewną akcję (np. nadał ataku­jące­mu dodatkowe uprawnienia). Więcej możesz znaleźc np. na wikipedii: http://pl.wikipedia.org/wiki/Cross-site_request_forgery .

W pliku spring-secu­ri­ty zamieni­amy poprzed­ni tag <http> na następujacy:

<http auto-config="true" use-expressions="true">
    <form-login login-page="/login"
        default-target-url="/profile"
        authentication-failure-url="/login?error=1"
        username-parameter="email"
        password-parameter="password" />
    <logout logout-success-url="/home" /> <!-- określamy przekierowanie po wylogowaniu -->
    <csrf /> <!-- włączamy zabezpieczenie przed csrf -->
</http>

Mamy tutaj kil­ka dodatkowych elementów:

  • logout — za pomocą atry­bu­tu logout-suc­cess-url określamy adres, na jaki użytkown­ik będzie przekierowany po poprawnym wylogowaniu 
    • więcej opcji zostało opisane na stron­ie http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#nsa-logout
  • csrf — ten tag akty­wu­je zabez­piecze­nie przed ataka­mi CSRF. Nieste­ty wyma­ga to, aby każdy for­mu­la­rz w naszej aplikacji zaw­ier­ał lin­ijkę (taką jak 3 od koń­ca na powyższym przykładzie) — jest to unikalny token gen­erowany za każdym razem przez naszą aplikację a następ­nie po przesła­niu for­mu­la­rza wery­fikowany (automaty­cznie przez Spring Security)
  • form-login — ten tag jest najbardziej intere­su­ją­cy, skon­fig­u­ru­je­my w nim kil­ka rzeczy: 
    • login-page — adres strony z for­mu­la­rzem logowania
    • default-tar­get-url — adres, na który użytkown­ik zostanie przekierowany po zal­o­gowa­niu (uwa­ga: domyśl­nie będzie to zabez­piec­zona strona, którą próbował odwiedz­ić, a która spowodowała przekierowanie na logowanie; jeśli takiej strony nie było, następu­je przekierowanie na tą stronę)
    • authen­ti­ca­tion-fail­ure-url — adres, na który przekierowu­je­my, jeśli były błędy w logowa­niu (np. zły login lub hasło)
    • user­name-para­me­ter, pass­word-para­me­ter — określa­ją nazwy pól z loginem i hasłem (czyli w HTM­Lu przekła­da się to na wartość atry­bu­tu name dla odpowied­nich tagów input)
    • więcej infor­ma­cji zna­jdziemy na stron­ie http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#nsa-form-login

W ten sposób skon­fig­urowal­iśmy włas­ny for­mu­la­rz logowa­nia — praw­da, że pros­to? :) Prze­jdźmy ter­az do zabez­piecza­nia metod.

Zabezpieczanie metod — adnotacja @Secured

Aby korzys­tać z tej adno­tacji musis­my dodać jeszcze jed­ną rzecz — i uwa­ga, doda­je­my ją tam, gdzie deklaru­je­my beany (np. kon­trol­ery), a więc w naszym przy­pad­ku w pliku applicationContext.xml.

Musimy dodać poniższą linijkę:

<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />

Pamię­ta­jąc, aby dodać pre­fiks secu­ri­ty w naszym XML (na górze pliku doda­je­my xmlns:security=”…”).

Pozwala to uży­wać adno­tacji @Secured nad naszy­mi meto­da­mi. Adno­tac­ja ta przyj­mu­je jako para­me­try nazwy ról, które mają dostęp do tej funkcjon­al­noś­ci. Nazwy te są tymi, które pobier­amy w drugim zapy­ta­niu przy auto­ryza­cji (patrz dru­ga część tej lekcji).

W tym miejs­cu warto tez zapamię­tać, że domyśl­nie nieza­l­o­gowany użytkown­ik posi­a­da role ROLE_ANONYMOUS (jeśli jest coś, co chcielibyśmy wyświ­et­lać tylko nieza­l­o­gowanym użytkownikom).

Korzystamy z danych o zalogowanym użytkowniku

W kodzie Javy

Bezpośred­nio w Javie Spring udostęp­nia obiekt Authen­ti­ca­tion, który może­my pobrać w następu­ją­cy sposób:

SecurityContextHolder.getContext().getAuthentication()

Posi­a­da on pole prin­ci­pal, które może byc obiek­tem typu Prin­ci­pal, a może też być Stringiem (stąd deklarac­ja jako Object). Pole to jest Stringiem, jeżeli użytkown­ik nie jest zal­o­gowany. Może­my więc uży­wać tej właś­ci­woś­ci do rozróżnienia, czy oso­ba korzys­ta­ją­ca ze strony jest zal­o­gowana czy też nie.

W widokach

W widokach mamy dostęp­ne dwa tagi — jeden do kon­trolowa­nia wyświ­et­la­nia pewnych ele­men­tów oraz dru­gi, do wyświ­et­la­nia danych o zal­o­gowanym użytkown­iku.

<sec:authorize access="hasRole('ROLE_USER')">
    Informacja tylko dla zalogowanych
</sec:authorize>

Powyższy kod wyświ­etli dany frag­ment tylko dla użytkown­ików, którzy posi­ada­ja rolę ROLE_USER.

<sec:authentication property="principal.username" />

Z kolei ten kod pozwala wyświ­etlić infor­ma­c­je o zal­o­gowanym użytkown­iku (takie jak np. login uży­ty pod­czas logowania)

Podsumowanie

Dzisiejsza część kończy lekc­je o zabez­piecza­niu aplikacji — dzie­ki temu możesz juz dodać uwierzytel­ni­an­ie i auto­ryza­c­je w swo­jej wlas­nej aplikacji :) Nie zapom­nij o tym, aby umożli­wić rejestrację!

Zadanie

Zabez­piecz swo­ją aplikację — te metody, które powin­ny być dostęp­ne tylko dla zal­o­gowanego użytkown­i­ka zabez­piecz z uży­ciem adno­tacji @Secured. Poza tym skon­fig­u­ruj włas­ny for­mu­la­rz logowa­nia — taki, żeby pasował wiz­ual­nie do strony :)

Licencja Creative Commons

Jeśli uważasz powyższą lekcję za przy­dat­ną, mamy małą prośbę: pol­ub nasz fan­page. Dzię­ki temu będziesz zawsze na bieżą­co z nowy­mi treś­ci­a­mi na blogu ( i oczy­wiś­cie, z nowy­mi częś­ci­a­mi kur­su Javy). Dzięki!