2012-09-19 18 views
5

Tengo una página JSF que no está protegida por j_security_check. Realizo los siguientes pasos:ViewExpiredException no lanzada en la solicitud ajax si la página JSF está protegida por j_security_check

  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 genera un ViewExpiredException, como se esperaba.

la publicación:

javax.faces.ViewState=8887124636062606698:-1513851009188353364 

Respuesta:

<partial-response> 
<error> 
<error-name>class javax.faces.application.ViewExpiredException</error-name> 
<error-message>viewId:/viewer.xhtml - View /viewer.xhtml could not be restored.</error-message> 
</error> 
</partial-response> 

Sin embargo, una vez que se configura la página de ser protegidos por j_security_check y realizar los mismos pasos mencionados anteriormente, por extraño que (para mí) el ViewExpiredException ya no se plantea. En cambio, la respuesta es solo un nuevo estado de vista.

la publicación:

javax.faces.ViewState=-4873187770744721574:8069938124611303615 

Respuesta:

<partial-response> 
<changes> 
<update id="javax.faces.ViewState">234065619769382809:-4498953143834600826</update> 
</changes> 
</partial-response> 

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.

Respuesta

7

Pude reproducir su problema. Lo que está sucediendo aquí es que el contenedor invoca un RequestDispatcher#forward() en 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, también se invocará el FacesServlet 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 es una solicitud de AJAX y no hay información de render (la solicitud de 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 era una página JSF (por ejemplo, JSP o HTML simple), la solicitud ajax habría devuelto la salida HTML completa de la página como respuesta ajax que no puede ser extraída por JSF ajax e interpretada como " vacío "respuesta".

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.

se puede lograr esto con un PhaseListener de la 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); 
      } 
     } 
    } 
} 

actualización esta solución se OmniFaces 1.2 ya ha integrado en el OmniPartialViewContext. Entonces, si ya usa OmniFaces, este problema es fully transparently resuelto y no necesita un PhaseListener personalizado para esto.

+0

Gracias BalusC. Me salvó el día. –

+0

De nada. – BalusC

+0

Oh, una pregunta adicional, me pregunto por qué sucede lo siguiente: si uso context.getExternalContext(). Redirect (loginURL), de hecho me redirige a la página de inicio de sesión. Pero después de iniciar sesión, el navegador muestra un archivo xml, con ViewState como su contenido. El archivo xml es exactamente el mismo que el segundo archivo xml que publiqué en mi pregunta. Si uso context.getExternalContext(). Redirect (homepageURL), todo funciona bien. Me llevará la página de inicio de sesión. Una vez que haya iniciado sesión, se mostrará la página de inicio. –

Cuestiones relacionadas