Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果JSF页面受j_安全检查保护,则不会在ajax请求上引发ViewExpiredException_Ajax_Jsf 2_J Security Check_Viewexpiredexception - Fatal编程技术网

如果JSF页面受j_安全检查保护,则不会在ajax请求上引发ViewExpiredException

如果JSF页面受j_安全检查保护,则不会在ajax请求上引发ViewExpiredException,ajax,jsf-2,j-security-check,viewexpiredexception,Ajax,Jsf 2,J Security Check,Viewexpiredexception,我有一个JSF页面不受j\u security\u check的保护。我执行以下步骤: 在浏览器中打开JSF页面 重新启动服务器 单击JSF页面上的命令按钮启动ajax调用 Firebug显示如预期的那样引发了一个ViewExpiredException 职位: javax.faces.ViewState=8887124636062606698:-1513851009188353364 javax.faces.ViewState=-4873187770744721574:80699381246

我有一个JSF页面不受
j\u security\u check
的保护。我执行以下步骤:

  • 在浏览器中打开JSF页面
  • 重新启动服务器
  • 单击JSF页面上的命令按钮启动ajax调用 Firebug显示如预期的那样引发了一个
    ViewExpiredException

    职位:

    javax.faces.ViewState=8887124636062606698:-1513851009188353364
    
    javax.faces.ViewState=-4873187770744721574:8069938124611303615
    
    答复:

    <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>
    
    <partial-response>
    <changes>
    <update id="javax.faces.ViewState">234065619769382809:-4498953143834600826</update>
    </changes>
    </partial-response>
    
    答复:

    <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>
    
    <partial-response>
    <changes>
    <update id="javax.faces.ViewState">234065619769382809:-4498953143834600826</update>
    </changes>
    </partial-response>
    
    
    234065619769382809:-4498953143834600826
    

    有人能帮我弄清楚吗?我希望它引发一个异常,这样我就可以处理该异常并显示一个错误页面。现在它只是用一个新的ViewState进行响应,我的页面只是被卡住了,没有任何视觉反馈。

    我能够重现您的问题。这里发生的情况是,容器调用了一个
    RequestDispatcher#forward()
    ,以访问安全约束中指定的登录页面。但是,如果登录页面本身也是一个JSF页面,那么转发的请求也会调用
    FacesServlet
    。由于请求是转发,这将在转发的资源(登录页面)上创建一个新视图。但是,由于这是一个ajax请求,并且没有
    render
    信息(整个POST请求基本上在安全性向前检查期间被丢弃),因此只会返回视图状态

    请注意,如果登录页面不是JSF页面(例如JSP或普通HTML),那么ajax请求会将页面的整个HTML输出作为ajax响应返回,这是JSF ajax无法解析的,并被解释为“空”响应

    不幸的是,它正在“按设计”工作。我怀疑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,那么这个问题就解决了,您不需要为此定制
    PhaseListener

    谢谢您,巴卢斯克。保存了我的一天。哦,还有一个问题,我想知道为什么会发生以下情况:如果我使用context.getExternalContext().redirect(loginURL),它确实会将我重定向到登录页面。但在登录后,浏览器会显示一个xml文件,其内容为ViewState。xml文件与第二个xml文件I完全相同 张贴在我的问题。如果我使用context.getExternalContext().redirect(homepageURL),一切正常。它将带我进入登录页面。登录后,将显示主页。没错,这是另一个棘手的问题:容器管理的身份验证会记住所有请求参数(包括无效的
    javax.faces.ViewState
    和另一个指示它是ajax请求的请求参数)并在成功登录后将其重新传递,这将导致一个作为ajax响应的
    ViewExpiredException
    错误页面。这可以通过重定向到转发URI来避免,而转发URI反过来应该通过普通GET请求而不是ajax POST请求重新触发安全检查。我已经相应地更新了答案。@BalusC OmniPartialViewContext对我没有任何帮助。Ajax发布到安全页面会导致403错误(而不是viewExpiredException),jsf Ajax处理程序会忽略该错误,因此不会发生任何事情。在JSF中处理过期视图时,似乎不可能在服务器端执行任何操作。没有调用过滤器、错误处理程序或任何东西。有什么建议吗?thx的解决方案。这张支票是原版的吗=需要空值吗?对于我的web应用程序,request.getAttribute(RequestDispatcher.FORWARD\u request\u URI)始终为空