Primefaces DialogFramework - 如何显示位于WEB-INF中的对话框?

stg*_*stg 4 dialog web-inf primefaces jsf-2

我使用Primefaces DialogFramework

  • Primefaces 5.0
  • Mojarra 2.1.27
  • Glassfish 3.1.2.2 Build 5

我的问题是,如果用户知道我的对话框的位置,他可以直接通过URL访问它.我不希望这是可能的,所以我认为它可以将对话框放在我的web-app的WEB-INF文件夹中,但是现在,如果我想打开对话框,我会得到一个FileNotFound-Exception.

如果我的对话框位于某个常规文件夹中,则可以正常工作

RequestContext.getCurrentInstance().openDialog("/myfolder/mydialog"); 
// this works as expected
Run Code Online (Sandbox Code Playgroud)

但如果它位于WEB-INF中,则它不再起作用

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

我也尝试为此设置导航规则faces-config但是再次没有成功

<navigation-case>
    <from-outcome>mydialog</from-outcome>
    <to-view-id>/WEB-INF/mydialog.xhtml</to-view-id>
    <redirect />
</navigation-case>
Run Code Online (Sandbox Code Playgroud)

我如何打开位于WEB-INF文件夹中的对话框,或者根本不可能?提前致谢

Bal*_*usC 8

不幸的是,将PrimeFaces对话框架对话框放入/WEB-INF以防止直接访问确实不起作用.对话框完全在客户端加载.在打开对话框的POST请求中,JSF/PrimeFaces返回一个oncomplete脚本,其中包含对话框的(public!)URL到JavaScript/jQuery,后者又显示了一个基本对话框模板,<iframe>其URL设置为对话框URL,反过来加载内容.实际上,正在发送2个请求,第一个是获取对话框的URL,第二个是根据该URL中的URL获取对话框的内容<iframe>.

/WEB-INF如果没有回退到"传统"对话框方法<p:dialog>和通过JS/CSS进行条件显示,就无法保持对话框的存在.如果请求来自a <iframe>,则服务器端也无法根据某些标头进行验证,以便可以简单地阻止所有其他标头.你最接近的赌注是referer标题,但这可能是欺骗性的.

最小化滥用的一种方法是在请求对话时检查pfdlgcid请求参数(由...标识Constants.DIALOG_FRAMEWORK.CONVERSATION_PARAM)的存在.PrimeFaces即将表示"会话ID"的请求参数附加到对话URL.假设所有对话框都存储在一个文件夹中/dialogs,那么你可以使用一个简单的servlet过滤器完成这项工作.这是一个启动示例,在/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.
        }
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

但是,滥用者可能不是那么愚蠢并且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;
}
Run Code Online (Sandbox Code Playgroud)

然后将PrimeFaces DialogNavigationHandler源代码复制到您自己的包中,并在第62行之后添加以下行:

DialogFilter.getIds((HttpServletRequest) context.getExternalContext().getRequest()).add(pfdlgcid);
Run Code Online (Sandbox Code Playgroud)

替换<navigation-handler>faces-config.xml用定制的一个.

最后,改变方法中的if条件DialogFilter#doFilter()如下:

if (getIds(request).contains(id)) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,这可以防止滥用者尝试使用随机ID打开对话框.但是,这并不会阻止滥用者通过在打开对话框<iframe>后立即复制确切的URL 来尝试打开对话框.鉴于PrimeFaces对话框架的工作方式,没有办法防止这种情况发生.pfdlgcid当对话框即将返回父级时,您最多可以从会话中删除该值.但是,当纯JS意味着关闭对话框时,这也被绕过了.

总而言之,如果你真的,真的,想要避免最终用户能够单独打开对话框,那么你就无法绕过"传统" <p:dialog>方法.