2014-07-25 56 views
4

我使用Primefaces DialogFrameworkPrimefaces DialogFramework - 如何顯示位於WEB-INF中的對話框?

  • Primefaces 5.0
  • 鑽嘴魚科2.1.27
  • 的Glassfish 3.1.2.2構建5

我的問題是,如果用戶知道的位置我的對話框中,他可以通過URL直接訪問它。我不希望這是可能的,所以我認爲它可以把對話框放在我的web應用程序的WEB-INF文件夾中,但現在,如果我想打開對話框,我會得到一個FileNotFound-Exception。

如果我的對話框位於一些普通文件夾,它工作正常

RequestContext.getCurrentInstance().openDialog("/myfolder/mydialog"); 
// this works as expected 

,但如果它位於WEB-INF,這是行不通的任何再

RequestContext.getCurrentInstance().openDialog("/WEB-INF/mydialog",options,null); 
// this is causing a fileNotFoundException 

我也嘗試過爲此在faces-config中設置導航規則,但又沒有成功

<navigation-case> 
    <from-outcome>mydialog</from-outcome> 
    <to-view-id>/WEB-INF/mydialog.xhtml</to-view-id> 
    <redirect /> 
</navigation-case> 

如何打開位於WEB-INF文件夾中的對話框,或根本不可能? 在此先感謝

回答

8

不幸的是,將PrimeFaces對話框框架對話框in /WEB-INF in order to prevent direct access確實不起作用。對話框完全加載客戶端。在打開對話框的POST請求上,JSF/PrimeFaces返回一個oncomplete腳本,其中包含對話框的(public!)URL到JavaScript/jQuery,後者又顯示一個基本對話框模板,其中的的URL被設置爲對話框URL ,然後加載內容。在效果中,正在發送2個請求,第一個獲取對話框的URL,第二個獲取基於中該URL的對話框內容。

沒有辦法保持/WEB-INF中的對話框沒有回落到通過<p:dialog>和通過JS/CSS的條件顯示的「傳統」對話方式。如果請求來自,那麼服務器端也無法根據某些標頭進行驗證,因此所有其他標識都可能會被阻止。您最接近的投注是referer標題,但這可能是欺騙性的。

減少濫用的一種方法是在請求對話時檢查是否存在pfdlgcid請求參數(由Constants.DIALOG_FRAMEWORK.CONVERSATION_PARAM標識)。 PrimeFaces即將這個代表「對話ID」的請求參數附加到對話URL。假定所有的對話框存儲在一個文件夾/dialogs中,那麼你可以用簡單的servlet filter來完成這項工作。下面是一個啓動示例,當請求/dialogs/*而沒有pfdlgcid請求參數時,將發送HTTP 400錯誤。

@WebFilter("/dialogs/*") 
public class DialogFilter implements Filter { 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest request = (HttpServletRequest) req; 
     HttpServletResponse response = (HttpServletResponse) res; 
     String id = request.getParameter(Constants.DIALOG_FRAMEWORK.CONVERSATION_PARAM); 

     if (id != null) { 
      chain.doFilter(req, res); // Okay, just continue request. 
     } 
     else { 
      response.sendError(HttpServletResponse.SC_BAD_REQUEST); // 400 error. 
     } 
    } 

    // ... 
} 

然而,施虐者可能不會那麼愚蠢和正常流量中發現pfdlgcid請求參數,並且仍然提供該參數時,即使有一個隨機值可以單獨打開的對話框。我想過比較實際的pfdlgcid值與已知的值。我檢查了PrimeFaces DialogNavigationHandler源代碼,但不幸的是,PrimeFaces不會在會話中的任何位置存儲此值。您需要提供一個自定義DialogNavigationHandler實現,其中您將pfdlgcid值存儲在會話映射中,該映射又會在servlet過濾器中進行比較。

首先添加下面的方法將DialogFilter

public static Set<String> getIds(HttpServletRequest request) { 
    HttpSession session = request.getSession(); 
    Set<String> ids = (Set<String>) session.getAttribute(getClass().getName()); 

    if (ids == null) { 
     ids = new HashSet<>(); 
     session.setAttribute(getClass().getName(), ids); 
    } 

    return ids; 
} 

然後copypaste的PrimeFaces DialogNavigationHandler source code到自己的包和第62行後添加以下行:

DialogFilter.getIds((HttpServletRequest) context.getExternalContext().getRequest()).add(pfdlgcid); 

與更換<navigation-handler>faces-config.xml定製的。

最後,改變if條件在DialogFilter#doFilter()方法如下:

if (getIds(request).contains(id)) { 
    // ... 
} 

現在,這防止濫用者從嘗試與隨機ID打開對話框。但是,這不會阻止濫用者在打開對話框後立即通過複製準確的 URL來嘗試打開對話框。鑑於PrimeFaces對話框架的工作方式,無法防止這種情況發生。當對話框即將返回到父級時,最多可以從會話中刪除pfdlgcid值。但是,當對話框以純JS方式關閉時,這也被繞過。

總而言之,如果真的,真的是,想要避免最終用戶能夠單獨打開對話框,那麼您不能繞過「傳統」<p:dialog>方法。