|
Strona główna Zbieranina Serwisy Porady Projekty Humor sektora IT TODO Nowości Ostatnie zmiany Kontakt Find pages
Set your name in
UserPreferences Referenced by
JSPWiki v2.2.33
|
Java/Struts - jak ograniczyć dostęp do akcji dla (nie)zalogowanych użytkownikówTable of ContentsJak zwykle możliwych rozwiązań jest sporo, ale tylko kilka jest dobrych, a które konkretnie to już zależy od rozpatrywanego przypadku. Sprawdzenie na poziomie strony JSPMożna sprawdzić na poziomie strony JSP czy bieżący sesja bieżącego requestu posiada informacje o autoryzowanym użytkowniku. Ale... ale skoro już piszemy w Strutsach, to logiki nie umieszczamy w stronach JSP, one są do prezentacji danych. Rozwiązanie to więc odrzucamy.Sprawdzanie na poziomie akcjiTrywialne rozwiązanie. W metodzie execute piszemy odpowiedniego ifa...
if (request.getSession().getAttribute("userContext") == null) {
return mapping.findForward("loginPage");
}
Szukamy w sesji obiektu zapisanego pod kluczem userContext - i jeśli takiego nie ma, to znaczy, że user nie jest jeszcze zalogowany. Jeśli to wykryjemy, to przekierowujemy usera do strony logowania. Proste. Choć uciążliwe przy większej ilości akcji i w póżniejszym utrzymywaniu aplikacji. Oczywiście ww ifa można umieścić w metodzie w bazowej klasie akcji dla aplikacji, w jakiejś statycznej metodzie w klasie usługowej, itd, itd. Sprawdzanie na poziomie akcji i ExceptionHandlerIMO całkiem dobre i elastyczne rozwiązanie. Tworzymy metodę rzucającą odpowiedni wyjątek w wypadku niezalogowanego użytkownika, konfigurujemy Strutsy aby w razie takiego wyjątku przekierowały usera od odpowiedniej strony. Kod mamy wtedy czysty, modularny, bez zbędnych powiązań między klasami.Wymagane klasy i konfiguracje: Klasa wyjątku oznaczjącego niezalogowanego użytkownika. Istotne aby dziedziczyła po RuntimeException:
public class NotLoggedException extends RuntimeException {
private static final long serialVersionUID = -4643278568158900622L;
public NotLoggedException() {
super();
}
public NotLoggedException(String message, Throwable cause) {
super(message, cause);
}
public NotLoggedException(String message) {
super(message);
}
public NotLoggedException(Throwable cause) {
super(cause);
}
}
Klasa ExceptionHandler przechwytująca nasz wyjątek. Zapisuje w kontekście requestu dane o bieżącym requeście, mogą się przydać po zalogowaniu:
public class NotLoggedExceptionHandlerAction extends ExceptionHandler {
@Override
public ActionForward execute(Exception exception, ExceptionConfig config, ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws ServletException {
request.setAttribute("exception", exception);
request.setAttribute("form", form);
request.setAttribute("mapping", mapping);
return mapping.findForward("login");
}
Konfiguracja w struts-config.xml:
<global-exceptions>
<exception
key="opis_wyjatku_w_ApplicationResources.properties"
type="nasz.pakiet.NotLoggedException"
handler="nasz.pakiet.NotLoggedExceptionHandlerAction"
path="sciezka_do_strony_jsp"/>
</global-exceptions>
Tworzymy metodę w bazowej klasie akcji dla aplikacji:
protected void ensureLogin(HttpServletRequest request) {
/* getUserContext() zwraca kontekst użytkownika dla podanego requestu */
if (getUserContext(request) == null) {
throw new NotLoggedException();
}
}
I używamy jej w kodzie każdej akcji:
public ActionForward execute(.....) {
ensureLogin(request);
// i dalszy ciag kodu akcji
}
Użycie wyjątku dziedziczonego po RuntimeException zwalnia nas od pamiętania jakie wyjątki rzuczamu w metodzie, no i zgodne jest z całą filozofią wyjątków: w końcu jest to faktycznie wyjątek czasu wykonania. Sprawdzania na poziomie filtraSposób niezwiązany ze Strutsami, ale też dzięki temu uniwersalny i łatwy do dodania do dowolnej aplikacji, nawet tej tylko w JSP pisanej.Instalujemy w web.xml własny filtr i w samym web.xml mapujemy go na adresy stron zabezpieczanych, albo w kodzie filtra sprawdzamy czy adres requestu wskazuje na zabezpieczoną strone. Jeśli tak i jeśli sesja nie zawiera informacji o zalogowaniu to przekierowujemy usera na stronę do logowania. Uwaga! Jeśli zmapujemy filtr na wszystkie odwołania (/*) to będzie on wywoływany także dla grafik, arkuszy styli, itd. Być może, a raczej na 100% nie jest to, co chcemy osiągnąć. Pewnie rozsądnie byłoby sprawdzać bieżące odwołanie za pomocą wyrażeń regularnych. Podłączenie filtra (fragment pliku web.xml) wyłapującego odwołąnia do stron JSP: <filter> <filter-name>Authorization</filter-name> <filter-class>moj.pakiet.AuthorizationFilter</filter-class> </filter> <filter-mapping> <filter-name>Authorization</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> Można też rozważyć użycie komponentu Url Rewrite Filter Sprawdzanie na poziomie kontenera - J2EE SecuritySposób czasami najprostrzy, jednak nie zawsze sensowny. Można po prostu zostawić cała autoryzację kontenerowi serwletów. Niech on sam wyłapie niezalogowanych użytkowników, dokona ich autoryzacji i nie dopuści niezalogowanych do odpowiednich stron. Problem z tą metodą jest taki, że łatwo można określić do których akcji użytkownik ma mieć dostęp, trudno określić do jakich danych ma mieć dostęp. Dla przykładu: możemy ograniczyć dostęp do akcji /editArticle tylko do użytkowników z rolą np. editor. Za pomocą tego mechanizmu nie określimy już, że użytkownicy mogą edytować tylko artykuły przez nich napisane. Nis nie stoi oczywiście na przeszkodzie aby połączyć zarówno J2EE security (aby ogólnie ograniczyć dostęp do wybranych akcji), a już na innym poziomie określać prawa do konkretnych obiektów. Konfigurujemy więc aplikację określając jakie role są wymagane do wywołania określonych akcji/stron. Następnie przypisujemy zdefiniowanych użytkowników do naszych ról. Wymagane modyfikacje pliku web.xml:
<security-constraint>
<web-resource-collection>
<!-- mozna tutaj podawac wiele roznych czesci serwisu, podawac dostepne metody HTTP, maski, itd -->
<web-resource-name>token</web-resource-name>
<url-pattern>/auth1.jsp</url-pattern>
</web-resource-collection>
<!-- określamy jakie role są wymagane do dostępu -->
<auth-constraint>
<role-name>manager</role-name>
</auth-constraint>
</security-constraint>
<!-- jeszcze raz podajemy wszystkie wymagane role -->
<security-role>
<role-name>manager</role-name>
</security-role>
<login-config>
<!-- określamy jak ma być przerowadzane logowanie: BASIC oraz FORM -->
<auth-method>FORM</auth-method>
<!-- jeśli wybrano model FORM to należy podać adresy stron z formularzem -->
<realm-name>Logowanie przez formularz</realm-name>
<form-login-config>
<form-login-page>/login_page.jsp</form-login-page>
<form-error-page>/login_page.jsp?error=true</form-error-page>
</form-login-config>
</login-config>
Przy wyborze metody logowania FORM należy udostępnić jeszcze formularz w postaci: <form method="post" action="j_security_check"> <input type="text" name="j_username"/> <input type="password" name="j_password"/> <input type="submit"/> </form> Jeśli używamy strutsów, to dla każdej akcji w pliku struts-config.xml za pomocą atrybutu roles można podać jakie role są wymagane do wywołania takiej akcji. Osobną sprawą jest zdefiniowanie listy użytkowników na poziomie samego kontenera serwletów. Ta kwestia jest jednak zależna od modelu kontenera i nie jest określona przez specyfikację. Dla Tomcata odpowiedź można znaleźć tutaj: JavaTomcat_j2ee_security
|
||||||