注销后,所有受限制的页面仍然可用于浏览器历史记录,如何防止这种情况?

时间:2012-09-22 06:06:36

标签: jsf jsf-2 logout browser-history

这是我的退出方法:

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";
}

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

1 个答案:

答案 0 :(得分:6)

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

另一个问题是,当您致电response.setHeader()时,您基本上覆盖任何以前设置的标头。您不希望这样做,如果must-revalidateno-cache不存在,则no-store完全没有效果。您需要将值commaseparated设置为单个标头,或使用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中的网址格式。

完成后,您的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";
}