JSPWiki logo
Strona główna
Zbieranina
Serwisy
Porady
Projekty
Humor sektora IT
TODO
Nowości
Ostatnie zmiany
Kontakt

Find pages
Unused pages
Undefined pages
Page Index

Set your name in
UserPreferences

Edit this page


Referenced by
Porady




JSPWiki v2.2.33


Java Struts_akcje_logowanie


Java/Struts - jak ograniczyć dostęp do akcji dla (nie)zalogowanych użytkowników

Jak 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 JSP

Moż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 akcji

Trywialne 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 ExceptionHandler

IMO 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 filtra

Sposó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 Security

Sposó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




Go to top   Edit this page   More info...   Attach file...
This page last changed on 05-Dec-2006 11:58:49 GMT by mikolajr.