#16.3 – zabezpieczanie aplikacji z użyciem Spring Security

By 1 lutego 2015Kurs Javy
Wpis-Header lekcje (2)

W poprzednich częściach tej lekcji mówiliśmy o samej koncepcji Spring Security oraz o tym, jak skonfigurować aplikację, aby z niego korzystała. Dzisiaj dowiemy się, jak wykorzystać tą konfigurację w naszej aplikacji :)

Dzisiaj trzecia i ostatnia część tej lekcji – zobaczymy, jak używać SpringSecurity w praktyce w naszej aplikacji. Po tej lekcji będziesz wiedziała, jak zabezpieczyć wybrane strony, wyświetlić ładny formularz logowania i zmieniać zachowanie Spring Security. Przejdźmy więc do samej lekcji :)

Lekcja

Konfiguracja własnego formularza logowania

W poprzedniej lekcji korzystaliśmy z formularza logowania wygenerowanego przez Springa – dzisiaj zmienimy to w taki sposób, aby używać własnego.

Przede wszystkim potrzebujemy widoku, który będzie wyświetlał rzeczony formularz – nie musi to być jakiś specjalny widok, integracja polega na tym, że wysyłamy odpowiednio spreparowane dane pod odpowiedni adres. W tym miejscu zakładam, że sama dopasujesz swój szablon – przedstawiony przykład może wyglądać u Ciebie inaczej, ale realnie ważne są głównie atrybuty ‚name’ pól oraz ‚action’ całego formularza. Układ wizualny, kolejność pól i style nie mają znaczenia :) Będziemy więc pracować 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>

Pierwsza linia ustawia zmienną EL o nazwie loginUrl i wpisuje do niej wartość – adres URL wygenerowany dla adresu względnego /j_spring_security_check . Trzecia linijka od końca to zabezpieczenie przed CSRF – włączymy to zabezpieczenie w naszej konfiguracji.

CSRF to jedna z metod ataku na aplikacje webowe, który polega na takim przekierowaniu użytkownika (w sposób niewidoczny), żeby wykonał bez świadomości pewną akcję (np. nadał atakującemu dodatkowe uprawnienia). Więcej możesz znaleźc np. na wikipedii: http://pl.wikipedia.org/wiki/Cross-site_request_forgery .

W pliku spring-security zamieniamy poprzedni 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 kilka dodatkowych elementów:

  • logout – za pomocą atrybutu logout-success-url określamy adres, na jaki użytkownik będzie przekierowany po poprawnym wylogowaniu
    • więcej opcji zostało opisane na stronie http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#nsa-logout
  • csrf – ten tag aktywuje zabezpieczenie przed atakami CSRF. Niestety wymaga to, aby każdy formularz w naszej aplikacji zawierał linijkę (taką jak 3 od końca na powyższym przykładzie) – jest to unikalny token generowany za każdym razem przez naszą aplikację a następnie po przesłaniu formularza weryfikowany (automatycznie przez Spring Security)
  • form-login – ten tag jest najbardziej interesujący, skonfigurujemy w nim kilka rzeczy:
    • login-page – adres strony z formularzem logowania
    • default-target-url – adres, na który użytkownik zostanie przekierowany po zalogowaniu (uwaga: domyślnie będzie to zabezpieczona strona, którą próbował odwiedzić, a która spowodowała przekierowanie na logowanie; jeśli takiej strony nie było, następuje przekierowanie na tą stronę)
    • authentication-failure-url – adres, na który przekierowujemy, jeśli były błędy w logowaniu (np. zły login lub hasło)
    • username-parameter, password-parameter – określają nazwy pól z loginem i hasłem (czyli w HTMLu przekłada się to na wartość atrybutu name dla odpowiednich tagów input)
    • więcej informacji znajdziemy na stronie http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#nsa-form-login

W ten sposób skonfigurowaliśmy własny formularz logowania – prawda, że prosto? :) Przejdźmy teraz do zabezpieczania metod.

Zabezpieczanie metod – adnotacja @Secured

Aby korzystać z tej adnotacji musismy dodać jeszcze jedną rzecz – i uwaga, dodajemy ją tam, gdzie deklarujemy beany (np. kontrolery), a więc w naszym przypadku w pliku applicationContext.xml.

Musimy dodać poniższą linijkę:

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

Pamiętając, aby dodać prefiks security w naszym XML (na górze pliku dodajemy xmlns:security=”…”).

Pozwala to używać adnotacji @Secured nad naszymi metodami. Adnotacja ta przyjmuje jako parametry nazwy ról, które mają dostęp do tej funkcjonalności. Nazwy te są tymi, które pobieramy w drugim zapytaniu przy autoryzacji (patrz druga część tej lekcji).

W tym miejscu warto tez zapamiętać, że domyślnie niezalogowany użytkownik posiada role ROLE_ANONYMOUS (jeśli jest coś, co chcielibyśmy wyświetlać tylko niezalogowanym użytkownikom).

Korzystamy z danych o zalogowanym użytkowniku

W kodzie Javy

Bezpośrednio w Javie Spring udostępnia obiekt Authentication, który możemy pobrać w następujący sposób:

SecurityContextHolder.getContext().getAuthentication()

Posiada on pole principal, które może byc obiektem typu Principal, a może też być Stringiem (stąd deklaracja jako Object). Pole to jest Stringiem, jeżeli użytkownik nie jest zalogowany. Możemy więc używać tej właściwości do rozróżnienia, czy osoba korzystająca ze strony jest zalogowana czy też nie.

W widokach

W widokach mamy dostępne dwa tagi – jeden do kontrolowania wyświetlania pewnych elementów oraz drugi, do wyświetlania danych o zalogowanym użytkowniku.

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

Powyższy kod wyświetli dany fragment tylko dla użytkowników, którzy posiadaja rolę ROLE_USER.

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

Z kolei ten kod pozwala wyświetlić informacje o zalogowanym użytkowniku (takie jak np. login użyty podczas logowania)

Podsumowanie

Dzisiejsza część kończy lekcje o zabezpieczaniu aplikacji – dzieki temu możesz juz dodać uwierzytelnianie i autoryzacje w swojej wlasnej aplikacji :) Nie zapomnij o tym, aby umożliwić rejestrację!

Zadanie

Zabezpiecz swoją aplikację – te metody, które powinny być dostępne tylko dla zalogowanego użytkownika zabezpiecz z użyciem adnotacji @Secured. Poza tym skonfiguruj własny formularz logowania – taki, żeby pasował wizualnie do strony :)

Licencja Creative Commons

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!

  •  
  •  
  •  
  •  
  •  
  • Ola

    Cześć,
    mam problem.dla

    mi wszystko działa, niestety jak zrobię

    nie działa wchodzą mi dane w formularzu logowania :(

    Byłabym wdzięczna za pomoc w czym może być problem.

    Pozdrawiam

    • Pytanie czy w logach coś się pojawia o jakimś błędzie? Oraz czy w bazie danych istnieją poprawne dane i czy jest możliwa komunikacja z tą bazą danych? W wolnej chwili zerkniemy też na projekt, który załączyłaś w drugim komentarzu i postaramy sie sprawdzić, co może być nie tak :)

  • Faktycznie zakradł się błąd – domyślny adres na który należy wysłać formularz to /login w Spring Security, a użyty przez nas /j_spring_security_check był konwencją używaną przez dłuższy czas. Rozwiązać można to na dwa sposoby:
    1. (zalecany) zmień w pliku login.jsp na
    2. w security-context.xml zamień na

    • Ola

      Już zmieniłam :)
      Ale i tak działa tylko przy użyciu

      • Sprawdź, czy na pewno masz poprawnie wszystko w bazie danych – ja użyłem poniższego skryptu do zainicjowania i wypełnienia jej danymi:
        http://pastebin.com/Wua5WiBW

        • Ola

          Miałam taki sam skrypt :)
          Później dodałam jeszcze pole authority_id i stworzyłam tabelę authority

  • Ola

    Czy wie ktoś może jak naprawić to by działało przy użyciu a nie ?