ViewExpiredException no lanzada en la solicitud ajax si la página JSF está protegida por j_security_check

Tengo una página JSF que no está protegida por j_security_check . Realizo los siguientes pasos:

  1. Abra la página JSF en un navegador.
  2. Reinicia el servidor.
  3. Haga clic en un botón de comando en la página JSF para iniciar una llamada ajax.

Firebug muestra que se ViewExpiredException una ViewExpiredException , como se esperaba.

Enviar:

 javax.faces.ViewState=8887124636062606698:-1513851009188353364 

Respuesta:

   class javax.faces.application.ViewExpiredException viewId:/viewer.xhtml - View /viewer.xhtml could not be restred.   

Sin embargo, una vez que configuro la página para ser protegida por j_security_check y realizo los mismos pasos enumerados anteriormente, extrañamente (para mí) ya no se ViewExpiredException la ViewExpiredException . En cambio, la respuesta es solo un nuevo estado de vista.

Enviar:

 javax.faces.ViewState=-4873187770744721574:8069938124611303615 

Respuesta:

   234065619769382809:-4498953143834600826   

¿Puede alguien ayudarme a resolver esto? Espero que genere una excepción, así que puedo procesar esa excepción y mostrar una página de error. Ahora solo responde con un nuevo ViewState, mi página simplemente se atascó sin ningún comentario visual.

Pude reproducir tu problema. Lo que sucede aquí es que el contenedor invoca un RequestDispatcher#forward() a la página de inicio de sesión como se especifica en la restricción de seguridad. Sin embargo, si la página de inicio de sesión también es una página JSF, se FacesServlet también en la solicitud reenviada. Como la solicitud es un reenvío, esto simplemente creará una nueva vista en el recurso reenviado (la página de inicio de sesión). Sin embargo, como se trata de una solicitud de AJAX y no hay información de render (la solicitud POST completa se descarta básicamente durante el control de seguridad), solo se devolverá el estado de la vista.

Tenga en cuenta que si la página de inicio de sesión no fuera una página JSF (por ejemplo, JSP o HTML simple), la solicitud ajax habría devuelto todo el resultado HTML de la página como una respuesta ajax que no puede ser extraída por JSF ajax e interpretada como respuesta “vacía”.

Desafortunadamente, funciona “como está diseñado”. Sospecho que hay algo de supervisión en las especificaciones JSF en cuanto a las verificaciones de restricción de seguridad en las solicitudes ajax. La causa es, después de todo, comprensible y, afortunadamente, fácil de resolver. Solo que, en realidad, no desea mostrar una página de error aquí, sino simplemente la página de inicio de sesión en su totalidad, exactamente como ocurriría durante una solicitud que no sea Ajax. Solo tiene que verificar si la solicitud actual es una solicitud AJAX y se reenvió a la página de inicio de sesión, luego debe enviar una respuesta AJAX especial “redireccionar” para que se modifique toda la vista.

Puede lograr esto con un PhaseListener siguiente manera:

 public class AjaxLoginListener implements PhaseListener { @Override public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } @Override public void beforePhase(PhaseEvent event) { // NOOP. } @Override public void afterPhase(PhaseEvent event) { FacesContext context = event.getFacesContext(); HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest(); String originalURL = (String) request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); String loginURL = request.getContextPath() + "/login.xhtml"; if (context.getPartialViewContext().isAjaxRequest() && originalURL != null && loginURL.equals(request.getRequestURI())) { try { context.getExternalContext().invalidateSession(); context.getExternalContext().redirect(originalURL); } catch (IOException e) { throw new FacesException(e); } } } } 

Actualice esta solución porque OmniFaces 1.2 se ha integrado en el OmniPartialViewContext . Entonces, si ya usa OmniFaces, este problema se resuelve completamente de forma transparente y no necesita un PhaseListener personalizado para esto.