2012-09-19 29 views
5

Tôi có trang JSF không được bảo vệ bởi j_security_check. Tôi thực hiện các bước sau:ViewExpiredException không được đưa lên yêu cầu ajax nếu trang JSF được bảo vệ bởi j_security_check

  1. Mở trang JSF trong trình duyệt.
  2. Khởi động lại máy chủ.
  3. Nhấp vào nút lệnh trên trang JSF để bắt đầu cuộc gọi ajax.

Firebug cho thấy rằng ViewExpiredException được tăng lên, như mong đợi.

bài viết:

javax.faces.ViewState=8887124636062606698:-1513851009188353364 

đáp ứng:

<partial-response> 
<error> 
<error-name>class javax.faces.application.ViewExpiredException</error-name> 
<error-message>viewId:/viewer.xhtml - View /viewer.xhtml could not be restored.</error-message> 
</error> 
</partial-response> 

Tuy nhiên, một khi tôi cấu hình trang để được bảo vệ bởi j_security_check và thực hiện các bước tương tự nêu trên, kỳ lạ (đối với tôi) ViewExpiredException không còn được nâng lên nữa. Thay vào đó, phản hồi chỉ là một trạng thái xem mới.

bài viết:

javax.faces.ViewState=-4873187770744721574:8069938124611303615 

đáp ứng:

<partial-response> 
<changes> 
<update id="javax.faces.ViewState">234065619769382809:-4498953143834600826</update> 
</changes> 
</partial-response> 

Ai đó có thể giúp tôi con số này ra? Tôi hy vọng nó sẽ tăng một ngoại lệ để tôi có thể xử lý ngoại lệ đó và hiển thị một trang lỗi. Bây giờ nó chỉ đáp ứng với một ViewState mới, trang của tôi đã bị kẹt mà không có bất kỳ phản hồi trực quan nào.

Trả lời

7

Tôi đã có thể tạo lại sự cố của bạn. Những gì đang xảy ra ở đây là container gọi RequestDispatcher#forward() đến trang đăng nhập như được chỉ định trong ràng buộc bảo mật. Tuy nhiên, nếu trang đăng nhập cũng là một trang JSF, thì FacesServlet cũng sẽ được gọi ra trên yêu cầu được chuyển tiếp. Khi yêu cầu được chuyển tiếp, điều này sẽ chỉ tạo một chế độ xem mới trên tài nguyên được chuyển tiếp (trang đăng nhập). Tuy nhiên, vì đó là yêu cầu ajax và không có thông tin render (toàn bộ yêu cầu POST về cơ bản bị hủy trong quá trình kiểm tra bảo mật về phía trước), chỉ trạng thái xem sẽ được trả về. Lưu ý rằng nếu trang đăng nhập không phải là trang JSF (ví dụ: JSP hoặc HTML thuần túy), thì yêu cầu ajax sẽ trả về toàn bộ đầu ra HTML của trang dưới dạng phản hồi ajax không được JSF ajax giải thích và được hiểu là " trống "phản hồi.

Thật không may, hoạt động "như được thiết kế". Tôi nghi ngờ rằng có một số giám sát trong đặc tả JSF như để kiểm tra ràng buộc an ninh trên các yêu cầu ajax. Nguyên nhân là sau khi tất cả dễ hiểu và may mắn dễ dàng để giải quyết. Chỉ, bạn thực sự không muốn hiển thị trang lỗi ở đây, nhưng thay vào đó chỉ toàn bộ trang đăng nhập, chính xác như sẽ xảy ra trong một yêu cầu không phải là ajax. Bạn chỉ cần kiểm tra xem yêu cầu hiện tại có phải là yêu cầu ajax và được chuyển tiếp tới trang đăng nhập hay không, sau đó bạn cần gửi phản hồi ajax "chuyển hướng" đặc biệt để toàn bộ chế độ xem sẽ được thay đổi.

Bạn có thể đạt được điều này với một PhaseListener như sau:

public class AjaxLoginListener implements PhaseListener { 

    @Override 
    public PhaseId getPhaseId() { 
     return PhaseId.RESTORE_VIEW; 
    } 

    @Override 
    public void beforePhase(PhaseEvent event) { 
     // NOOP. 
    } 

    @Override 
    public void afterPhase(PhaseEvent event) { 
     FacesContext context = event.getFacesContext(); 
     HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); 
     String originalURL = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); 
     String loginURL = request.getContextPath() + "/login.xhtml"; 

     if (context.getPartialViewContext().isAjaxRequest() 
      && originalURL != null 
      && loginURL.equals(request.getRequestURI())) 
     { 
      try { 
       context.getExternalContext().invalidateSession(); 
       context.getExternalContext().redirect(originalURL); 
      } catch (IOException e) { 
       throw new FacesException(e); 
      } 
     } 
    } 
} 

Cập nhật giải pháp này được kể từ OmniFaces 1.2 được xây dựng vào OmniPartialViewContext. Vì vậy, nếu bạn tình cờ sử dụng OmniFaces, thì vấn đề này là fully transparently được giải quyết và bạn không cần tùy chỉnh PhaseListener cho việc này.

+0

Cảm ơn bạn BalusC. Đã lưu ngày của tôi. –

+0

Bạn được chào đón. – BalusC

+0

Oh một câu hỏi bổ sung, tôi tự hỏi tại sao điều sau xảy ra: Nếu tôi sử dụng context.getExternalContext(). Redirect (loginURL), nó thực sự chuyển hướng tôi đến trang đăng nhập. Nhưng sau khi đăng nhập, một tệp xml, với ViewState là nội dung của nó, được trình duyệt hiển thị. Tệp xml chính xác giống như tệp xml thứ hai tôi đã đăng trong câu hỏi của mình. Nếu tôi sử dụng context.getExternalContext(). Redirect (homepageURL), tất cả đều hoạt động tốt. Nó sẽ đưa tôi trang đăng nhập. Sau khi đăng nhập, trang chủ sẽ được hiển thị. –

Các vấn đề liên quan