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

Bas*_*suz 1 jsf logout browser-history jsf-2

这是我的注销方法:

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";
}
Run Code Online (Sandbox Code Playgroud)

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

Bal*_*usC 6

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

另一个问题是,当你打电话时response.setHeader(),你基本上覆盖任何以前设置的标题.你不想这样做,将must-revalidate有完全若没有效果no-cacheno-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).
}
Run Code Online (Sandbox Code Playgroud)

此示例假定/app/*URL模式后面的所有受限页面都可用.如果你是不同的,例如/secured/*,/user/*,/admin/*等等,那么你需要改变的URL模式@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";
}
Run Code Online (Sandbox Code Playgroud)