2009-12-17 56 views
12

Tôi đang làm một diễn đàn đơn giản với một loạt các Servlets mà mỗi trang đại diện cho một trang chủ, chủ đề, postedit, đăng nhập và trang danh sách người dùng. Trên một số trang này có một liên kết xuất hiện khi người dùng không đăng nhập.Chuyển hướng trở lại trang sau khi đăng nhập

Điều tôi muốn đạt được là kích hoạt chuyển hướng (sử dụng forward() trên RequestDispatcher) sau khi đăng nhập để trình duyệt quay lại trang nơi người dùng trước khi nhấp vào liên kết đăng nhập. Để làm được điều này, tôi thấy hai giải pháp.

Giải pháp đầu tiên là phải có HTML Form bằng nút đăng nhập và trường ẩn sẽ chứa thông tin sẽ cho biết trang nào sẽ chuyển hướng là Parameter. Điều này là doable nhưng tôi muốn thử cái gì khác.

Giải pháp thứ hai là thêm Attribute vào session đại diện cho "trang" đầu tiên theo một cách nào đó. Điều này có thể chứa một String nhưng điều này không khác với cách tiếp cận đầu tiên. Một thay đổi khác là thêm một tham chiếu đến HttpServlet và sử dụng instanceof hoặc một biến String tĩnh có thể được sử dụng để nhận dạng Servlet theo một cách nào đó. Tuy nhiên, điều này sẽ yêu cầu tạo một lớp tổ tiên chung cho tất cả các Servlets.

Có lẽ có một giải pháp đơn giản khác mà bạn có thể thấy sẽ tạo thành sự thỏa hiệp tốt? Hoặc, có lẽ một trong các giải pháp trên là hoàn toàn có thể chấp nhận được?

Trả lời

24

Tôi muốn ưu tiên đầu tiên ở trên giải pháp thứ hai. Đây là số yêu cầu thông tin phạm vi và thực sự không thuộc về phiên, nó sẽ chỉ dẫn đến "wtf?" trải nghiệm khi bạn mở nhiều cửa sổ/tab trong cùng một phiên.

Mở liên kết đến trang đăng nhập, chỉ cần vượt qua URL hiện như yêu cầu tham số:

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

Hoặc nếu nó là một hình thức POST đến trang đăng nhập:

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

Trong đăng nhập , chuyển nó sang yêu cầu tiếp theo dưới dạng biến ẩn:

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

Trong servlet đăng nhập, hãy sử dụng nó :

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

Khá đơn giản, phải không? :)

Một số có thể đề xuất sử dụng request.getHeader("referer") cho mục này bên trong biểu mẫu đăng nhập thay vì request.getRequestURI() trong liên kết/nút trước khi đăng nhập, nhưng tôi sẽ không làm điều đó vì điều này được khách hàng kiểm soát và không phải lúc nào cũng trả về thông tin đáng tin cậy . Một số khách hàng đã tắt hoặc đang sử dụng một số phần mềm giả mạo phần mềm có giá trị không hợp lệ, chẳng hạn như hầu hết các sản phẩm Symantec (ho).

+0

Câu trả lời hay, cộng với nó cho tôi một ảnh chụp nhanh về những gì cần nhắm đến khi một DAO được thêm vào. –

+0

Nếu bạn đang sử dụng bảo mật được quản lý container thì việc gửi yêu cầu tới j_security_check sẽ không cho phép bạn thực hiện điều này; thay vào đó sử dụng Servlet phiên bản 3 đăng nhập có lập trình: HttpServletRequest.login – Ryan

+0

Cảm ơn bạn rất nhiều. –

3

Nếu bạn muốn làm điều này với các trang, trang đăng nhập của bạn có thể xem tiêu đề (sic) trong yêu cầu đã tải (request.getHeader("referer")) để xem đó có phải là trang trên trang web của bạn hay không tiêu đề bị thiếu - sử dụng một loại mặc định). Sau đó, nó sẽ lưu trữ URL đó (tôi có thể sử dụng một trường ẩn, như bạn đã nói, trong biểu mẫu đăng nhập; nhưng một phiên var cũng sẽ hoạt động). Khi đăng nhập hoàn tất, hãy chuyển hướng đến URL được lưu trữ.

Những ngày này, tôi có thể sử dụng tất cả điều đó như một cơ chế dự phòng nếu tôi không thể đăng nhập bằng cách phủ một hộp thoại trên trang và đăng nhập qua Ajax - và như vậy, không bao giờ rời khỏi trang .


Sửa Hoặc tốt hơn, như Bozho chỉ ra, mã hóa các trang mục tiêu vào liên kết của bạn đến trang đăng nhập. Mặc dù đó là không đúng là IE không đặt tiêu đề "giới thiệu" (không), người giới thiệu không bắt buộc và có thể bị tắt và vì bạn đã tự động tạo trang liên kết với biểu mẫu đăng nhập, tại sao lại dễ bị tổn thương cho rằng nếu bạn không cần phải.

+1

không cần phải có trình giới thiệu và IE không xảy ra. Vì vậy, chuyển hướng đến một trang mặc định trong 50 +% các trường hợp không phải là thích hợp hơn – Bozho

+0

IE8 dường như trả lại cùng một giá trị giới thiệu như Firefox. Từ trả lời của bạn, tôi tưởng tượng rằng đây không phải là trường hợp với các phiên bản khác của IE. –

+1

@Bozho: Không chắc chắn bạn đang đề cập đến điều gì (um, như đã có). Chỉ cần thử nghiệm nó để chắc chắn: IE6 đặt nó, IE7 đặt nó, IE8 đặt nó. –

1

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

chương: Ứng dụng dòng chảy trên xác thực thành công và thất bại

... Nếu xác thực thành công, kết quả đối tượng xác thực sẽ được đặt vào SecurityContextHolder. Trình xác thực AuthenticationSuccessHandler được định cấu hình sau đó sẽ được gọi để chuyển hướng hoặc chuyển tiếp người dùng đến đích đích. Theo mặc định, một SavedRequestAwareAuthenticationSuccessHandler được sử dụng, có nghĩa là người dùng sẽ được chuyển hướng đến đích ban đầu mà họ yêu cầu trước khi họ được yêu cầu đăng nhập. ...

+0

Cảm ơn Nils. Tôi đã thử nghiệm với Spring nên điều này sẽ hữu ích sau này. –

1

Sử dụng trường ẩn trong biểu mẫu khá chuẩn. Tại sao thử phát minh lại bánh xe?

+0

Vâng, đó là một thực hành tiêu chuẩn với HTML nhưng tôi không chắc chắn như vậy khi nói đến các ứng dụng web. Ngoài ra, một lý do để phát minh lại bánh xe là hiểu rõ hơn tại sao bánh xe lại cần ở nơi đầu tiên;) –

4

Cách tiếp cận được đề xuất đầu tiên của bạn là phương pháp tốt nhất. Có một trường ẩn với value=request.getRequestURI() và chuyển hướng đến URI đó sau khi đăng nhập.

Sử dụng referer sẽ không hoạt động, vì IE (ít nhất một số phiên bản của nó) không đặt tiêu đề referer.

Lưu trữ thông số trong phiên sẽ gây ra hành vi lạ nếu người dùng mở nhiều tab.

Edit: Để minh họa cho câu hỏi tốt hơn:

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

Hầu hết các câu trả lời giả định rằng một "đăng nhập" liên kết/nút được nhấn vào, và sau đó là trang đăng nhập được mở ra. Đây chỉ là một mặt của câu chuyện. Trong trường hợp đó, URL tài nguyên ban đầu có thể được thêm dưới dạng tham số và được đặt trong biểu mẫu đăng nhập (trong trường ẩn).

Nhưng trong trường hợp chuyển tiếp từ tài nguyên được bảo vệ đến trang đăng nhập, trường ẩn phải chứa URL yêu cầu ngay lập tức.

Điều này, tất nhiên, không phải là những gì trong câu hỏi, nhưng cuối cùng sẽ phát sinh như một tình huống và cần được xem xét là tốt.

+0

Um, * những gì * phiên bản? Tài liệu tham khảo? Tôi vừa thử nghiệm IE6, IE7 và IE8. Tất cả đều làm. (Không phải là sẽ không tốt hơn để mã hóa liên kết vào URL cho trang đăng nhập.) –

+0

Có biểu mẫu chỉ để mã hóa liên kết ngược có vẻ quá mức cần thiết. Chỉ cần mã hóa nó trong liên kết biểu mẫu đăng nhập dưới dạng tham số truy vấn. –

+0

Hầu hết khách hàng đặt tiêu đề người giới thiệu, nhưng tất nhiên, nó có thể được ghi đè/đặt thành trống ở phía máy khách, vì vậy tôi chắc chắn sẽ đi theo số request.getRequestURI() Ben

0

Ok, đây là những gì tôi đã làm. Đăng nhập là quá trình gồm hai bước với một Servlet hiển thị biểu mẫu và một điều khiển khác nếu kết hợp tên người dùng + mật khẩu là chính xác. Cả hai có thể được kết hợp.

Một tham số có thể được gửi thông qua một hình thức hoặc thông qua một liên kết (JSP đã không được thêm vào nào):

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

Các tham số sau đó được lấy ra như sau:

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

Khi thông tin đăng nhập đã được kiểm tra, việc chuyển hướng có thể được thực hiện như sau:

RequestDispatcher rd = request.getRequestDispatcher(redirectionPath); 

if(rd != null) 
    rd.forward(request, response); 
Các vấn đề liên quan