46 votes

Délai d'expiration de la session et traitement des exceptions ViewExpiredException sur les requêtes ajax JSF/PrimeFaces

Je trouve cet article utile pour les demandes non-ajax. Comment gérer l'expiration de la session et l'exception ViewExpiredException dans JSF 2 ? mais je ne peux pas l'utiliser lorsque je soumets un appel AJAX.

Supposons que dans une boîte de dialogue primefaces, j'effectue une demande de post en utilisant AJAX et que la session a déjà expiré. Je vois ma page se bloquer.

Comment résoudre ce genre de scénario de telle sorte que, lorsque je publie un message en utilisant AJAX, je puisse le rediriger vers ma page de visualisation expirée et puis le rediriger vers la page de connexion, de manière similaire à la solution proposée dans le lien ci-dessus ?

JSF2/Primefaces/Glassfish

52voto

BalusC Points 498232

Les exceptions qui sont lancées pendant les requêtes ajax n'ont par défaut aucune réaction du côté client. Ce n'est que lorsque vous exécutez Mojarra avec l'étape du projet définie sur Development et utiliser <f:ajax> alors vous obtiendrez une alerte JavaScript simple avec le type d'exception et le message. Mais à part cela, et dans PrimeFaces, il n'y a par défaut aucun retour d'information. Vous pouvez toutefois voir l'exception dans le journal du serveur et dans la réponse ajax (dans la section "Network" de la boîte à outils du développeur du navigateur Web).

Vous devez implémenter un ExceptionHandler qui fait essentiellement le travail suivant quand il y a une ViewExpiredException dans la file d'attente :

String errorPageLocation = "/WEB-INF/errorpages/expired.xhtml";
context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation));
context.getPartialViewContext().setRenderAll(true);
context.renderResponse();

Alternativement, vous pouvez utiliser la bibliothèque utilitaire JSF OmniFaces . Il dispose d'un FullAjaxExceptionHandler dans ce but précis (code source aquí , démonstration de la vitrine aquí ).

Voir aussi :

0 votes

Salut BalusC..Merci toujours. J'ai parcouru le lien Omnifaces et je voudrais juste demander s'il n'y aura pas de conflit si j'utilise déjà Primefaces et que j'ajoute Omnifaces dans le mélange ? En ce qui concerne ma question, je dois encore lire le FullAjaxExceptionHandler

1 votes

Absolument pas. De plus, l'application Showcase utilise PrimeFaces. OmniFaces est simplement une bibliothèque d'utilitaires dont les utilitaires ne peuvent être utilisés que par votre propre commande/configuration.

1 votes

Merci BalusC vous êtes exceptionnellement utile !

18voto

Douglas Junior Points 486

Une fusion entre la réponse de @BalusC et celle de ce poste J'ai résolu mon problème !

Mon ExceptionHandlerWrapper :

public class CustomExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    CustomExceptionHandler(ExceptionHandler exception) {
        this.wrapped = exception;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }

    @Override
    public void handle() throws FacesException {
        final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
        while (i.hasNext()) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context
                    = (ExceptionQueuedEventContext) event.getSource();

            // get the exception from context
            Throwable t = context.getException();

            final FacesContext fc = FacesContext.getCurrentInstance();
            final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
            final NavigationHandler nav = fc.getApplication().getNavigationHandler();

            //here you do what ever you want with exception
            try {

                //log error ?
                //log.log(Level.SEVERE, "Critical Exception!", t);
                if (t instanceof ViewExpiredException) {
                    requestMap.put("javax.servlet.error.message", "Session expired, try again!");
                    String errorPageLocation = "/erro.xhtml";
                    fc.setViewRoot(fc.getApplication().getViewHandler().createView(fc, errorPageLocation));
                    fc.getPartialViewContext().setRenderAll(true);
                    fc.renderResponse();
                } else {
                    //redirect error page
                    requestMap.put("javax.servlet.error.message", t.getMessage());
                    nav.handleNavigation(fc, null, "/erro.xhtml");
                }

                fc.renderResponse();
                // remove the comment below if you want to report the error in a jsf error message
                //JsfUtil.addErrorMessage(t.getMessage());
            } finally {
                //remove it from queue
                i.remove();
            }
        }
        //parent hanle
        getWrapped().handle();
    }
}

Mon ExceptionHandlerFactory :

public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {

    private ExceptionHandlerFactory parent;

    // this injection handles jsf
    public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getExceptionHandler() {
        ExceptionHandler handler = new CustomExceptionHandler(parent.getExceptionHandler());
        return handler;
    }

}

Mon faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">

    <factory>
        <exception-handler-factory>
            your.package.here.CustomExceptionHandlerFactory
        </exception-handler-factory>
    </factory>
</faces-config>

3voto

RajV Points 727

J'utilise Mojarra 2.1.7 en mode Production avec JBoss 7. Après l'expiration de la session, les appels AJAX renvoient un document XML d'erreur. Vous pouvez facilement attraper cette erreur en utilisant le gestionnaire habituel onerror de f:ajax.

<script type="text/javascript">
    function showError(data) {
        alert("An error happened");
        console.log(data);
    }
</script>

<h:commandLink action="...">
    <f:ajax execute="..." render="..." onerror="showError"/>
</h:commandLink>

4 votes

Vous devriez ajouter ce gestionnaire à chaque f/p:ajax de votre page. Ce n'est pas une solution viable.

1 votes

@ukaszL vous pouvez aussi utiliser jsf.ajax.addOnError (en javascript) pour l'ajouter globalement.

0 votes

Également sujet à des erreurs si, par exemple, votre console n'est pas ouverte dans IE.

1voto

Ramya Points 11

J'ai inclus ceci dans ma classe ViewExpiredExceptionHandler et cela a bien fonctionné pour moi dans WAS.

    public void handle() throws FacesException {
    FacesContext facesContext = FacesContext.getCurrentInstance();
                 for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents()
            .iterator(); iter.hasNext();) {
        Throwable exception = iter.next().getContext().getException();

        if (exception instanceof ViewExpiredException) {

            final ExternalContext externalContext = facesContext
                    .getExternalContext();

            try {

                facesContext.setViewRoot(facesContext.getApplication()
                        .getViewHandler()
                        .createView(facesContext, "/Login.xhtml"));     //Login.xhtml is the page to to be viewed. Better not to give /WEB-INF/Login.xhtml
                externalContext.redirect("ibm_security_logout?logoutExitPage=/Login.xhtml");    //  when browser back button is pressed after session timeout, I used this.         
                facesContext.getPartialViewContext().setRenderAll(true);
                facesContext.renderResponse();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                iter.remove();
            }
        }

    }

    getWrapped().handle();
}

J'espère que cela vous aidera

1voto

Rami Points 1

J'ai été confronté à ce problème, le besoin d'afficher un popup de confirmation lorsque l'utilisateur fait une action après que la session soit terminée, la solution que j'ai proposée était la suivante :

<security:http use-expressions="true" auto-config="true" entry-point-ref="authenticationEntryPoint">
            <security:intercept-url pattern="/common/auth/**" access="permitAll" />
            <security:intercept-url pattern="/javax.faces.resource/**" access="permitAll" />
            <security:intercept-url pattern="/**/   *.*" access="hasRole('ROLE_ADMIN')" />
            <security:form-login login-page="/common/auth/login.jsf" />
            <!-- <security:remember-me key="secret" services-ref="rememberMeServices" /> -->
            <security:logout invalidate-session="true" logout-success-url="/common/auth/login.jsf" />
        </security:http>
        <bean id="authenticationEntryPoint" class="com.x.y.MyRedirectEntryPoint" >
           <property name="loginFormUrl" value="/common/auth/login.jsf"/>
        </bean>

Le point d'entrée MyRedirectEntryPoint doit étendre AuthenticationProcessingFilterEntryPoint et surcharger la méthode de début.

public void commence(HttpServletRequest request, HttpServletResponse response,   AuthenticationException authException)
        throws IOException, ServletException {
    boolean ajaxRedirect = request.getHeader("faces-request") != null
            && request.getHeader("faces-request").toLowerCase().indexOf("ajax") > -1;
    if (ajaxRedirect) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            response.sendError(403);

        }
    } else {

        super.commence(request, response, authException);
    }
}

Maintenant, vous pouvez simplement lier une fonction javascript de rappel pour attraper l'erreur 403 et faire ce que vous voulez :

$(document).bind('ajaxError',
                    function(event, request, settings, exception){
                          if (request.status==403){
                             //do whatever you wanted may be show a popup or just redirect
                             window.location = '#{request.contextPath}/';
                             }
                             });

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X