不幸的是,为了防止直接访问而放入/WEB-INF
PrimeFaces Dialog Framework 对话框确实行不通。对话框完全加载在客户端。在打开对话框的 POST 请求中,JSF/PrimeFaces 将带有对话框oncomplete
的(公共!)URL 的脚本返回给 JavaScript/jQuery,然后显示一个基本对话框模板,<iframe>
其 URL 设置为对话框 URL,其中反过来加载内容。实际上,发送了 2 个请求,第一个请求获取对话框的 URL,第二个请求基于<iframe>
.
/WEB-INF
如果不退回到<p:dialog>
通过 JS/CSS 的“传统”对话框方法和条件显示,就无法保持对话框。如果请求来自 ,服务器端也无法根据某些标头进行验证<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.
}
}
// ...
}
但是,滥用者可能没有那么愚蠢,并且pfdlgcid
在正常流程中发现请求参数,并且在提供该参数时仍然能够单独打开对话框,即使使用随机值也是如此。我想将实际pfdlgcid
值与已知值进行比较。我检查了 PrimeFacesDialogNavigationHandler
源代码,但不幸的是,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;
}
然后将PrimeFacesDialogNavigationHandler
源代码复制粘贴到您自己的包中,并在第 62 行之后添加以下行:
DialogFilter.getIds((HttpServletRequest) context.getExternalContext().getRequest()).add(pfdlgcid);
用定制的替换<navigation-handler>
in 。faces-config.xml
最后,改变方法中的if
条件DialogFilter#doFilter()
如下:
if (getIds(request).contains(id)) {
// ...
}
现在,这可以防止施虐者尝试使用随机 ID 打开对话框。<iframe>
然而,这并不能阻止施虐者通过在打开对话框后立即复制粘贴确切的 URL来尝试打开对话框。鉴于 PrimeFaces 对话框架的工作方式,没有办法阻止这种情况。pfdlgcid
当对话框即将返回父级时,您最多可以从会话中删除该值。但是,当通过纯 JS 方式关闭对话框时,这也被绕过了。
总而言之,如果您真的,真的,想要避免最终用户能够单独打开对话框,那么您就不能绕过“传统”<p:dialog>
方法。