【问题标题】:After logout, all restricted pages are still available in browser history, how to prevent that?注销后,浏览器历史记录中所有受限页面仍然可用,如何防止?
【发布时间】:2012-09-22 06:06:35
【问题描述】:

这是我的注销方法:

public String logout() throws IOException, ServletException 
{
    FacesContext context = FacesContext.getCurrentInstance();
    ExternalContext ec = context.getExternalContext();
    HttpSession session = (HttpSession) ec.getSession(false);
    HttpServletResponse response = (HttpServletResponse) ec.getResponse();
    final HttpServletRequest request = (HttpServletRequest)ec.getRequest();
    session.invalidate();
    Cookie[] cookies = request.getCookies();  
    Cookie opentoken = null;  
    for(Cookie c : cookies){  
        if (c.getName().equals("opentoken")){ 
            if (session != null){  
            opentoken = c;  
            opentoken.setMaxAge(0);  
            opentoken.setValue("");  
            response.addCookie(opentoken);
            response.sendRedirect(request.getContextPath()); 
            response.setHeader("Pragma", "no-cache"); 
            response.setHeader("Cache-Control", "no-cache"); 
            response.setHeader("Cache-Control", "no-store"); 
            response.setHeader("Cache-Control", "must-revalidate"); 
            response.setHeader("Expires", "Mon, 8 Aug 2006 10:00:00 GMT");//past date 
            }
            break;  
        }
    }
    context.getExternalContext().getSessionMap().remove("#{LogoutBean}");
    return "login.xhtml?faces-redirect=false";
}

调用此方法后,浏览器历史中的导航仍然有效。我该如何解决这个问题?

【问题讨论】:

  • 使用“filterChain.doFilter(request, response);”有帮助吗?清除缓存后的语句?但是我怎样才能从 xhtml 即从调用位置获取 filterchain 对象??

标签: jsf jsf-2 logout browser-history


【解决方案1】:

当您设置响应标头时,它仅适用于 当前 响应,而不适用于所有先前的响应(受限页面)或未来的响应(重定向(!)及之后的响应)。您实际上想在受限请求的所有响应中关闭浏览器缓存。事实上,正如您在评论中猜到的那样,您应该为此使用 servlet filter

另一个问题是,当您调用response.setHeader() 时,您基本上覆盖 任何先前设置的标题。你不想这样做,如果no-cacheno-store 不存在,must-revalidate 完全没有效果。您需要将逗号分隔的值设置为单个标头,或使用response.addHeader()

总而言之,你的 webapp 中应该有一个这样的类:

@WebFilter("/app/*")
public class NoCacheFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
        response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
        response.setDateHeader("Expires", 0); // Proxies.
        chain.doFilter(req, res);
    }

    // ... (just implement init() and destroy() with empty bodies).
}

此示例假定所有受限页面都在/app/* URL 模式后面可用。如果你的不同,例如/secured/*/user/*/admin/*等,则需要相应地更改@WebFilter中的URL模式。

完成后,您的logout() 可以简化如下:

public String logout() {
    ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
    ec.invalidateSession();

    if (ec.getRequestCookieMap().get("opentoken") != null) {
        ec.addResponseCookie("opentoken", null, Collections.<String, Object>singletonMap("maxAge", 0));
    }

    return "login.xhtml?faces-redirect=true";
}

【讨论】:

  • 它是 Servlet 3.0 / Java EE 6 的一部分,已经推出了将近 3 年。如果您仍在使用旧的 Servlet 2.5,那么您需要在 web.xml 中使用老式的 &lt;filter&gt;&lt;filter-mapping&gt;。另请参阅我的答案第 1 段末尾的“servlet 过滤器”链接。
  • 我已经做到了:loginFiltergreenprint.admin.NoCacheFilterloginFilter/user/* 仍然报错“属性当我使用 @WebFilter("/user/*") 时,bean 中的注释类型 WebFilter" 的值未定义。我现在能做什么?请帮助
  • 在注销方法中存在另一个错误- ec.addResponseCookie("opentoken", null,Collections.singletonMap("maxAge", 0));给出一个错误提示-“ExternalContext 类型中的方法 addResponseCookie(String, String, Map) 不适用于参数 (String, null, Map)”。请提出任何解决方案...
  • 您是否在 IDE 中生成了注释? :o 只需删除注释。例如,您是否仔细阅读过 servlet 过滤器 wiki 页面?至于泛型错误,我已经更新了答案。
  • 仍然无法使会话失效,并且历史记录保持不变.. 后退和前进按钮仍然有效! :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-02
  • 2015-02-05
  • 2012-04-14
  • 2012-04-23
  • 2020-01-30
  • 1970-01-01
  • 2010-09-22
相关资源
最近更新 更多