2009-12-17 36 views
12

Robię proste forum z serią Servlets, z których każda reprezentuje stronę domową, temat, postit, login i listę użytkowników. Na niektórych z tych stron znajduje się odsyłacz, który pojawia się, gdy użytkownik nie jest zalogowany.Przekierowanie z powrotem do strony po zalogowaniu

Co chciałbym osiągnąć, to wywołać przekierowanie (używając funkcji forward() na RequestDispatcherze) po zalogowaniu, aby przeglądarka powraca do strony, na której był użytkownik przed kliknięciem linku logowania. W tym celu widzę dwa rozwiązania.

Pierwszym rozwiązaniem jest posiadanie kodu HTML Form z przyciskiem logowania i niewidocznym polem, które będzie zawierało informację, która strona zostanie przekierowana jako Parameter. Jest to możliwe, ale chciałbym spróbować czegoś innego.

Drugim rozwiązaniem jest dodanie Attribute do session, która w pewien sposób reprezentuje pierwszą "stronę". Może to zawierać String, ale nie różni się to od pierwszego podejścia. Innym skrętem byłoby dodanie odwołania do HttpServlet i użycie instanceof lub statycznej zmiennej String, która mogłaby zostać użyta do zidentyfikowania Servleta w jakiś sposób. Jednak wymagałoby to stworzenia wspólnej klasy przodków dla wszystkich Servlets.

Być może istnieje jeszcze jedno proste rozwiązanie, które można uznać za dobry kompromis? A może jedno z powyższych rozwiązań jest całkowicie dopuszczalne?

Odpowiedz

24

Wolałbym pierwsze nad drugim rozwiązaniem. To jest żądanie zasięg informacji i naprawdę nie należy do sesji, doprowadziłoby to tylko do "wtf?" doświadczenia, gdy masz wiele okien/kart otwartych w tej samej sesji.

na link do strony logowania, po prostu przekazać aktualny adres URL żądania parametru:

<a href="/login?from=${pageContext.request.requestURI}">Login</a> 

Lub jeśli jest to forma POST do strony logowania:

<input type="hidden" name="from" value="${pageContext.request.requestURI}"> 

W logowania formularz, prześlij go do następnego żądania jako zmienną ukrytą:

<input type="hidden" name="from" value="${param.from}"> 

Z serwletu logowania skorzystaj z niego :

User user = userDAO.find(username, password); 
if (user != null) { 
    request.getSession().setAttribute("user", user); 
    response.sendRedirect(request.getParameter("from")); 
} else { 
    // Show error. 
} 

Dość proste, prawda? :)

Niektórzy mogą zasugerować użycie request.getHeader("referer") w formularzu logowania zamiast request.getRequestURI() w łączu/przycisku przed zalogowaniem, ale nie zrobiłbym tego, ponieważ jest on sterowany przez klienta i nie zawsze zwraca wiarygodne informacje . Niektórzy klienci je wyłączyli lub używają oprogramowania, które fałszuje je z nieprawidłową wartością, na przykład większość (kaszel). Produkty firmy Symantec mają.

+0

Świetna odpowiedź, plus daje mi migawkę o tym, do czego należy dążyć po dodaniu DAO. –

+0

Jeśli używasz zabezpieczeń zarządzanych przez kontener, wtedy wysłanie żądania do j_security_check nie pozwoli ci tego zrobić; zamiast tego użyj programowego logowania w Servlet 3: HttpServletRequest.login – Ryan

+0

Dziękuję bardzo. –

3

Jeśli chcesz to zrobić ze stronami, twoja strona logowania może zobaczyć nagłówek referer (sic) w żądaniu, które go załadowało (request.getHeader("referer")), aby sprawdzić, czy jest to strona w twojej witrynie (jeśli nie - lub jeśli brakuje nagłówka - użyj jakiejś wartości domyślnej). Następnie zapisałby ten URL (prawdopodobnie użyłbym ukrytego pola, jak powiedziałeś, w formularzu logowania, ale var sesji też by działał). Po zakończeniu logowania wyślij przekierowanie do zapisanego adresu URL.

W dzisiejszych czasach prawdopodobnie użyłbym tego jako mechanizmu rezerwowego, gdybym nie mógł wykonać logowania, nakładając okno dialogowe na stronę i logując się przez Ajax - i tak, nigdy nie opuszczając strony w ogóle .


Edit Albo jeszcze lepiej, jak Bozho wskazuje zakodowanie strony docelowej w linku do strony logowania. Chociaż jest to nie prawdziwe, że IE nie ustawia nagłówka "referer" (tak), referer nie jest wymagany i może być wyłączony, a ponieważ już dynamicznie tworzysz stronę łączącą się z formularzem logowania, po co być wrażliwym do tego, jeśli nie musisz.

+1

referer nie jest wymagany, a IE go nie ustawia. Zatem przekierowanie do strony domyślnej w 50 +% przypadków nie jest preferowane. – Bozho

+0

Wygląda na to, że IE8 zwraca tę samą wartość odniesienia, co Firefox. Z twojej odpowiedzi wyobrażam sobie, że tak nie jest w przypadku innych wersji IE. –

+1

@Bozho: Nie jestem pewien, o czym mówisz (um, tak jak było). Po prostu przetestowałem to, aby upewnić się: IE6 ustawia to, IE7 ustawia to, IE8 ustawia to. –

1

od: http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.pdf

rozdziale: Application Flow w Authentication sukcesów i niepowodzeń

... Jeśli uwierzytelnianie zakończy się pomyślnie, otrzymany przedmiot uwierzytelniania zostaną umieszczone w SecurityContextHolder. Skonfigurowany AuthenticationSuccessHandler zostanie wywołany w celu przekierowania lub przekazania użytkownika do odpowiedniego miejsca docelowego. Domyślnie używany jest SavedRequestAwareAuthenticationSuccessHandler, co oznacza, że ​​użytkownik zostanie przekierowany do miejsca docelowego, którego zażądał, zanim zostanie poproszony o zalogowanie się. ...

+0

Dzięki Nils. Eksperymentowałem ze Spring, więc będzie to przydatne później. –

1

Używanie ukrytego pola w formularzu jest dość standardowe. Po co próbować odkrywać nowe koło?

+0

Tak, to standardowa praktyka z HTML, ale nie byłem pewien, czy chodzi o aplikacje internetowe. Ponadto, jednym z powodów, aby odświeżyć koło, jest lepsze zrozumienie, dlaczego kierownica była potrzebna;) –

4

Twoje pierwsze sugerowane podejście jest najlepsze. Masz ukryte pole z numerem value=request.getRequestURI() i przekierowanie do tego identyfikatora URI po zalogowaniu.

Używanie referer nie będzie działać, ponieważ IE (przynajmniej niektóre z jego wersji) nie ustawi nagłówka referer.

Przechowywanie parametru w sesji spowoduje dziwne zachowanie, jeśli użytkownik otworzy wiele kart.

Edit: Aby zilustrować pytanie lepiej:

some resource -> (requests protected resource) -> (gets forwarded to the login page) -> (should be redirected to the original resource)

Większość odpowiedzi zakładają, że "login"/przycisk kliknięciu łącza, a następnie strona logowania jest otwarty. To tylko jedna strona historii. W takim przypadku oryginalny URL zasobu może zostać dodany jako parametr i umieszczony w formularzu logowania (w ukrytym polu).

Ale w przypadku przekazanie z chronionego zasobu do strony logowania, ukryte pole powinno zawierać natychmiastowy adres URL żądania.

To oczywiście nie jest to, co jest w pytaniu, ale ostatecznie powstanie jako sytuacja i powinno być również brane pod uwagę.

+0

Um, * jakie * wersje? Odniesienie? Właśnie testowałem IE6, IE7 i IE8. Wszyscy to robią. (Nie znaczy to, że nie byłoby lepiej zakodować link do adresu URL strony logowania.) –

+0

Posiadanie formularza do kodowania linku wstecznego wydaje się przesadą. Po prostu zakoduj go w łączu formularza logowania jako parametr zapytania. –

+0

Większość klientów ustawia nagłówek referer, ale oczywiście można go przesłonić/ustawić jako puste po stronie klienta, więc na pewno pójdę na request.getRequestURI() Ben

0

OK, oto co zrobiłem. Logowanie jest dwuetapowym procesem z jednym serwletem, który pokazuje formularz, a inny kontroluje, czy kombinacja nazwa użytkownika i hasło jest poprawna. Oba można połączyć.

parametr może być wysłany za pomocą formularza lub za pośrednictwem łącza (JP nie zostały jeszcze dodane)

out.println("Login <a href='LoginServlet?comeback=home'>here</a><br>"); 

Parametr ten jest następnie pobierana w następujący sposób:

String comeback = request.getParameter("comeback"); 

Kiedy informacje logowania zostały sprawdzone, przekierowanie można wykonać w następujący sposób:

RequestDispatcher rd = request.getRequestDispatcher(redirectionPath); 

if(rd != null) 
    rd.forward(request, response); 
Powiązane problemy