我正在使用Primefaces DialogFramework和
我的问题是,如果用户知道我的对话框的位置,他可以直接通过URL访问它。我不希望这是可能的,所以我认为它可以将对话框放在我的web-app的WEB-INF文件夹中,但是现在,如果我想打开对话框,我会得到一个FileNotFound-Exception。 / p>
如果我的对话框位于某个常规文件夹中,则可以正常使用
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文件夹中的对话框,或者根本不可能? 提前致谢
答案 0 :(得分:8)
不幸的是,使用PrimeFaces对话框架对话框in /WEB-INF
in order to prevent direct access确实不起作用。对话框完全在客户端加载。在打开对话框的POST请求中,JSF / PrimeFaces返回一个oncomplete
脚本,其中包含对话框的(public!)URL到JavaScript / jQuery,后者又显示了一个带有<iframe>
的基本对话框模板其URL设置为对话框URL,后者又加载内容。实际上,正在发送2个请求,第一个是获取对话框的URL,第二个是根据<iframe>
中的URL获取对话框的内容。
没有办法在/WEB-INF
中保持对话,而不会通过<p:dialog>
回退到“传统”对话框方法,并通过JS / CSS进行条件显示。如果请求来自<iframe>
,服务器端也无法根据某些标头进行验证,以便可以简单地阻止所有其他标头。你最接近的赌注是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;
}
然后将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)) {
// ...
}
条件,如下所示:
<iframe>
现在,这可以防止滥用者尝试使用随机ID打开对话框。但是,这并不会阻止滥用者通过在打开后立即复制确切的pfdlgcid
URL来尝试打开对话框。鉴于PrimeFaces对话框架的工作方式,没有办法防止这种情况发生。当对话框即将返回父级时,您最多可以从会话中删除<p:dialog>
值。但是,当纯JS意味着关闭对话框时,这也被绕过了。
总而言之,如果你真的,真的,想要避免最终用户能够单独打开对话框,那么你就无法绕过“传统的”{{1}}方法。