我有一个不受保护的JSF页面j_security_check
。 我执行以下步骤:
- 在浏览器中打开JSF页面。
- 重新启动服务器。
- 点击JSF页面上的命令按钮来启动Ajax调用。
萤火显示, ViewExpiredException
上升,符合市场预期。
帖子:
javax.faces.ViewState=8887124636062606698:-1513851009188353364
响应:
<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>
但是,一旦我配置页面由被保护j_security_check
和执行上面列出的,奇怪的是相同的步骤(对我)的ViewExpiredException
不再提高。 相反,效应初探只是一个新的视图状态。
帖子:
javax.faces.ViewState=-4873187770744721574:8069938124611303615
响应:
<partial-response> <changes> <update id="javax.faces.ViewState">234065619769382809:-4498953143834600826</update> </changes> </partial-response>
谁能帮我想出解决办法? 我希望它抛出一个异常,所以我可以处理该异常,并显示一个错误页面。 现在,它只是一个新的ViewState的回应,我的网页只是卡住,没有任何视觉反馈。
我能够重现你的问题。 这到底是怎么发生的是,容器调用RequestDispatcher#forward()
在安全约束中指定的登录页面。 但是,如果登录页面本身就是一个JSF页面为好,那么FacesServlet
将被调用以及所转发的请求。 由于请求是前锋,这会简单地创建所转发的资源(登录页面)的新观点。 然而,因为它是一个Ajax请求,并没有render
信息(整个POST请求在安全检查过程中向前基本上丢弃),只有视图状态将被退回。
请注意,如果登录页面不是一个JSF页面(例如JSP或纯HTML),则AJAX请求将返回的页面作为Ajax响应其是由JSF AJAX不可解析的整个HTML输出和解释为“空”的响应。
这是不幸的是,工作“作为设计的”。 我猜想,有一个在JSF规范的一些监督作为对Ajax请求的安全约束检查。 原因毕竟是可以理解的,幸运的是容易解决。 只是,你其实并不想在这里显示错误页面,而只是将其全部登录页面,正如一个非Ajax请求期间会发生。 你只需要检查,如果当前请求是一个Ajax请求,并且被转发到登录页面,那么你需要使整个视图将改为发送一个特殊的“重定向” Ajax响应。
您可以通过实现这个PhaseListener
如下:
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);
}
}
}
}
更新此解决方案是因为OmniFaces 1.2被内置到OmniPartialViewContext
。 所以,如果你碰巧已经使用OmniFaces,那么这个问题是完全透明的解决,你并不需要一个定制PhaseListener
这一点。
文章来源: ViewExpiredException not thrown on ajax request if JSF page is protected by j_security_check