避免JSF Web应用程序上的后退button

我正在显示非常敏感的数据。 用户从我的服务器注销后,我不希望另一个用户能够看到数据击中浏览器的后退button。

我怎样才能做到这一点?

默认情况下,浏览器的后退button根本不会向服务器发送HTTP请求。 而是从浏览器caching中检索页面。 这基本上是无害的,但是对最终用户来说确实很混乱,因为他/她错误地认为它确实来自服务器。

所有你需要做的就是指示浏览器不caching受限制的页面。 你可以用一个简单的servletfilter来设置适当的响应头 :

@WebFilter public class NoCacheFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (!request.getRequestURI().startsWith(request.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc) 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); } // ... } 

(请注意,此filter会跳过JSF资源请求, 实际上需要单独configuration其caching )

为了让它在每个JSF请求上运行,假设在你的webapp的web.xml中的FacesServlet<servlet-name>的值是facesServlet ,那么在filter类上设置下面的注解:

 @WebFilter(servletNames={"facesServlet"}) 

或者,为了让它在一个特定的URL模式上运行,例如/app/*/private/*/secured/*等与限制页面相匹配的设置,在filter类上设置以下注释:

 @WebFilter("/app/*") 

你甚至可以在一个filter中完成相同的工作,如果你已经有一个filter检查login的用户。

如果您碰巧使用JSF实用程序库OmniFaces ,那么您也可以只抓住它的CacheControlFilter 。 这也透明地将JSF资源考虑在内。

也可以看看:

  • 防止用户在注销后看到先前访问的受保护页面
  • 会话过期授权redirect在提交JSF表单时不起作用,页面保持不变
  • JSF 2.0查看范围后退button安全吗?

我还发现了另一个好的解决scheme

在faces-config.xml中添加

 <lifecycle> <phase-listener id="nocache">client.security.CacheControlPhaseListener</phase-listener> </lifecycle> 

并实施以下课程:

 package client.security; import javax.faces.context.FacesContext; import javax.faces.event.PhaseEvent; import javax.faces.event.PhaseId; import javax.faces.event.PhaseListener; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class CacheControlPhaseListener implements PhaseListener { public PhaseId getPhaseId() { return PhaseId.RENDER_RESPONSE; } public void afterPhase(PhaseEvent event) { } public void beforePhase(PhaseEvent event) { FacesContext facesContext = event.getFacesContext(); HttpServletResponse response = (HttpServletResponse) facesContext .getExternalContext().getResponse(); response.addHeader("Pragma", "no-cache"); response.addHeader("Cache-Control", "no-cache"); // Stronger according to blog comment below that references HTTP spec response.addHeader("Cache-Control", "no-store"); response.addHeader("Cache-Control", "must-revalidate"); // some date in the past response.addHeader("Expires", "Mon, 8 Aug 2006 10:00:00 GMT"); } }