jsf browser back-button

Evitar el botón Atrás en la aplicación web JSF



browser back-button (2)

Estoy mostrando datos MUY sensibles. Después de que el usuario cierra la sesión de mi servidor, no quiero que otro usuario pueda ver los datos presionando el botón Atrás del navegador.

¿Cómo puedo conseguir esto?


De forma predeterminada, el botón Atrás del navegador no envía ninguna solicitud HTTP al servidor. En cambio, recupera la página de la memoria caché del navegador. Esto es esencialmente inofensivo, pero de hecho confunde al usuario final, porque piensa incorrectamente que realmente proviene del servidor.

Todo lo que necesita hacer es ordenar al navegador que no almacene en caché las páginas restringidas. Puede hacerlo con un filtro de servlet simple que establece los encabezados de respuesta apropiados :

@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); } // ... }

(tenga en cuenta que este filtro omite las solicitudes de recursos JSF, cuyo almacenamiento en caché en realidad debe configurarse por separado )

Para que se ejecute en cada solicitud de JSF, configure la siguiente anotación en la clase de filtro, suponiendo que el valor de <servlet-name> de FacesServlet en el web.xml su facesServlet es facesServlet :

@WebFilter(servletNames={"facesServlet"})

O bien, para que se ejecute solo en un patrón de URL específico, como el que coincide con las páginas restringidas, por ejemplo, /app/* , /private/* , /secured/* , etc., configure la siguiente anotación en la clase de filtro:

@WebFilter("/app/*")

Incluso podría hacer el mismo trabajo en un filtro que verifique el usuario conectado, si ya tiene uno.

Si usa la biblioteca de utilidades JSF OmniFaces , entonces también podría tomar su CacheControlFilter . Esto también tiene en cuenta de forma transparente los recursos JSF.

Ver también:


También encontré otra buena solución.

En faces-config.xml add

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

E implementa la siguiente clase:

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