会话失效后发生ViewExpiredException

时间:2018-12-11 07:34:22

标签: jsf primefaces jsf-2 jsf-2.2

我有一个使用Primefaces 6.0 / JSF 2.2的应用程序,其中有以下情形。

用户通过与应用程序中的@SessionScoped bean交互来登录,并被重定向到homepage.jsf。之后,用户通过菜单项(mypage.jsf)导航到页面。

public void login() throws IOException {

        //.... Authentication mechanism here 

        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
        externalContext.redirect(new StringBuilder(externalContext.getRequestContextPath())
                                .append("/homepage.jsf").toString());
        return;
}

然后,他从同一选项卡中退出应用程序,并自动重定向到登录页面。

public String logout() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    externalContext.invalidateSession();
    return "/login/login.jsf?faces-redirect=true";
}

注意:虽然登录/注销实现位于@SessionScoped处理程序中,但应用程序的其余操作/重定向位于@ViewScoped。

用户再次登录该应用程序,并尝试浏览之前(mypage.jsf)所在页面的同一p:menu项。

<p:menuitem value="" url="/mypage.jsf?faces-redirect=true" />

这时,应用程序通过javax.faces.application.ViewExpiredException:无法还原视图。在stackoverflow的众多帖子中对此行为进行了描述,其中一个会话在会话(javax.faces.application.ViewExpiredException: View could not be restored)无效之后给出了有关此行为的详细信息

我尝试过的事情: 我知道这无关紧要,并且在JSF 2.2上默认情况下将其设置为false,仍然尝试一下。

<context-param>
    <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
    <param-value>false</param-value>
</context-param>

手动设置会话中的视图数。请注意,只有1个或2个用户在该应用程序上工作,但以防万一。

<context-param>
    <description></description>
    <param-name>com.sun.faces.numberOfViewsInSession</param-name>
    <param-value>15</param-value>
</context-param>
<context-param>
    <description></description>
    <param-name>com.sun.faces.numberOfLogicalViews</param-name>
    <param-value>15</param-value>
</context-param>

此外,我已经创建了一个过滤器来避免缓存,如此处Prevent user from seeing previously visited secured page after logout

所述
@WebFilter(servletNames = { "facesServlet" })
public class LoginFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {

            HttpServletRequest req = (HttpServletRequest) request;

            HttpServletResponse res = (HttpServletResponse) response;
            res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP
            res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
            res.setDateHeader("Expires", 0); // Proxies.
            chain.doFilter(request, response);
            return;
    }
}

我认为将 javax.faces.STATE_SAVING_METHOD 设置为 client 可能会解决我的问题,但这是我要避免的事情。

此外,我创建了一个异常处理程序来处理Viewexpireexception并将用户重定向到特定页面。当然,这只是为了解决这种情况而不是解决问题。

更新1

我试图将ajax设置为false的commandLink进行“ mypage.jsf”上的重定向,以防万一这是一个问题,但具有完全相同的异常

<h:commandLink action="/mypagejsf?faces-redirect=true" ajax="false" value="My Link" />

更新2 首次注销并从登录页面分析请求标头后,我注意到以下内容:

1)浏览器上的sessionID与服务器上的sessionID匹配

2)Referer属性显示到以下URL http://..../mypage.jsf?faces-redirect=true。这是我尝试访问它时收到异常的页面。

更新3 我还注意到,当我尝试第二次登录后(在发生异常之前)访问mypage.jsf时,我的客户端请求(如果我没有记错的话)使用服务器上也存在的相同sessionId。发生异常时,服务器上的会话将被破坏并创建一个新会话。

0 个答案:

没有答案