Je trouve cet article utile pour les requêtes non-ajax Comment gérer l'expiration de session et ViewExpiredException dans JSF 2? mais je ne peux pas l'utiliser lorsque je soumets à l'aide de AJAX appel.
Supposons que dans une boîte de dialogue primefaces, je fasse une demande de publication en utilisant AJAX et la session a déjà expiré. Je vois ma page se bloquer.
Comment résoudre ce type de scénario tel que lorsque je poste avec AJAX, je peux le rediriger vers la page de vue expirée, puis le transférer vers la page de connexion similaire à la solution présentée dans le lien ci-dessus?
JSF2/Primefaces/Glassfish
Les exceptions levées lors de requêtes ajax n'ont par défaut aucun retour du côté client. Seulement lorsque vous exécutez Mojarra avec stage défini sur Development
et utilisez <f:ajax>
, vous recevrez alors une alerte JavaScript nue avec le type d’exception et le message. Mais à part cela, et dans PrimeFaces, il n'y a par défaut aucun retour. Vous pouvez toutefois voir l'exception dans le journal du serveur et dans la réponse ajax (dans la section "Réseau" de la boîte à outils pour développeurs du navigateur Web).
Vous devez implémenter une commande personnalisée ExceptionHandler
qui effectue essentiellement le travail suivant lorsqu'il y a un 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();
Vous pouvez également utiliser la bibliothèque d’utilitaires JSF OmniFaces . Il possède un FullAjaxExceptionHandler
dans ce but précis (code source ici , démonstration de la vitrine ici ).
Une fusion entre la réponse de @BalusC et ce post , 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;
}
}
Mes visages-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>
J'utilise Mojarra 2.1.7 en mode Production avec JBoss 7. Une fois la session expirée, AJAX appelle un document XML d'erreur. Vous pouvez facilement intercepter cette erreur en utilisant le gestionnaire onerror habituel 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>
J'ai inclus cela 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 t'aides
J'ai fait face à ce problème. Il est nécessaire d'afficher une fenêtre de confirmation lorsque l'utilisateur effectue une action après l'expiration de la session. La solution 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>
MyRedirectEntryPoint devrait étendre la méthode AuthenticationProcessingFilterEntryPoint et override
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 intercepter 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}/';
}
});