web-dev-qa-db-fra.com

Déconnexion / Déconnexion de la session avec la sécurité du printemps

J'utilise spring/spring-security 3.1 et je veux prendre des mesures chaque fois que l'utilisateur se déconnecte (ou si la session est expirée). J'ai réussi à faire l'action pour la déconnexion, mais pour le délai d'expiration de la session, je ne peux pas le faire fonctionner.

Dans web.xml, je n'ai que le ContextLoaderListener spécifié (cela peut-il être le problème?) Et bien sûr le DelegatingFilterProxy.

J'utilise la configuration automatique comme ça.

    <security:http auto-config="false" use-expressions="false">
    <security:intercept-url pattern="/dialog/*"
        access="ROLE_USERS" />
    <security:intercept-url pattern="/boa/*"
        access="ROLE-USERS" />
    <security:intercept-url pattern="/*.html"
        access="ROLE-USERS" />

    <security:form-login login-page="/auth/login.html"
        default-target-url="/index.html" />
    <security:logout logout-url="/logout"
         invalidate-session="true"
        delete-cookies="JSESSIONID" success-handler-ref="logoutHandler" />
</security:http>

<bean id="logoutHandler" class="com.bla.bla.bla.LogoutHandler">
    <property name="logoutUrl" value="/auth/logout.html"/>
</bean>

Le gestionnaire de déconnexion est appelé lorsque l'utilisateur clique sur déconnexion, ce qui fera des appels à une base de données.

Mais comment gérer le délai d'expiration de la session ???

Une façon de le gérer serait d'injecter le nom d'utilisateur dans la session lorsque l'utilisateur se connecte, puis d'utiliser un httpsessionlistener ordinaire et de faire la même chose lors de l'expiration de la session.

Existe-t-il une manière similaire avec la sécurité du printemps, de sorte que lorsque le printemps découvre que la session doit expirer, je peux m'y connecter, accéder à l'authentification et obtenir les détails utilisateur à partir de là et faire le nettoyage.

32
Perre

J'ai une solution plus simple. Cela fonctionne à la fois pour la déconnexion et l'expiration de la session.

@Component
public class LogoutListener implements ApplicationListener<SessionDestroyedEvent> {

    @Override
    public void onApplicationEvent(SessionDestroyedEvent event)
    {
        List<SecurityContext> lstSecurityContext = event.getSecurityContexts();
        UserDetails ud;
        for (SecurityContext securityContext : lstSecurityContext)
        {
            ud = (UserDetails) securityContext.getAuthentication().getPrincipal();
            // ...
        }
    }

}

web.xml:

<listener>
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
56
John29

Ok, j'ai une solution qui marche, ce n'est pas aussi bon que je le souhaiterais, mais ça m'amène au résultat.

Je crée un bean à partir duquel je peux obtenir le ApplicationContext.

public class AppCtxProvider implements ApplicationContextAware {
private static WeakReference<ApplicationContext> APP_CTX;

@Override
public void setApplicationContext(ApplicationContext applicationContext)
        throws BeansException {
    APP_CTX = new WeakReference<ApplicationContext>(applicationContext);
}

public static ApplicationContext getAppCtx() {
    return APP_CTX.get();
}
}

J'implémente HttpSessionEventPublisher et sur destroy, j'obtiens les UserDetails via sessionRegistry.getSessionInfo (sessionId)

J'ai maintenant les beans printaniers dont j'ai besoin pour nettoyer la session et l'utilisateur pour lequel la session a expiré.

public class SessionTimeoutHandler extends HttpSessionEventPublisher {
@Override
public void sessionCreated(HttpSessionEvent event) {
    super.sessionCreated(event);
}

@Override
public void sessionDestroyed(HttpSessionEvent event) {
    SessionRegistry sessionRegistry = getSessionRegistry();
    SessionInformation sessionInfo = (sessionRegistry != null ? sessionRegistry
            .getSessionInformation(event.getSession().getId()) : null);
    UserDetails ud = null;
    if (sessionInfo != null) {
        ud = (UserDetails) sessionInfo.getPrincipal();
    }
    if (ud != null) {
               // Do my stuff
    }
    super.sessionDestroyed(event);
}

private SessionRegistry getSessionRegistry() {
    ApplicationContext appCtx = AppCtxProvider.getAppCtx();
    return appCtx.getBean("sessionRegistry", SessionRegistry.class);
}
7
Perre

Vous pouvez utiliser SimpleRedirectInvalidSessionStrategy pour rediriger vers une URL lorsqu'une session demandée non valide est détectée par le SessionManagementFilter.

Exemple d'applicationContext serait comme ceci:

<http>
    <custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
<http>


<beans:bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
    <beans:constructor-arg name="securityContextRepository" ref="httpSessionSecurityContextRepository" />
    <beans:property name="invalidSessionStrategy" ref="simpleRedirectInvalidSessionStrategy " />
</beans:bean>

<beans:bean id="simpleRedirectInvalidSessionStrategy" class="org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy">
  <beans:constructor-arg name="invalidSessionUrl" value="/general/logins/sessionExpired.jsf" />
  <beans:property name="createNewSession" value="false" />
</beans:bean>
<beans:bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>

Si vous utilisez JSF, reportez-vous également à JSF 2, Spring Security 3.x et Richfaces 4 redirigent vers la page de connexion lors de l'expiration de la session pour les requêtes ajax sur la façon de gérer également les requêtes Ajax.

[~ # ~] update [~ # ~] : Dans un tel cas, vous pouvez étendre HttpSessionEventPublisher et écouter les événements sessionDestroyed comme ceci:

package com.examples;
import javax.servlet.http.HttpSessionEvent;

import org.springframework.security.web.session.HttpSessionEventPublisher;


public class MyHttpSessionEventPublisher extends HttpSessionEventPublisher {

   @Override
   public void sessionCreated(HttpSessionEvent event) {
      super.sessionCreated(event);
   }

   @Override
   public void sessionDestroyed(HttpSessionEvent event) {
      //do something
      super.sessionDestroyed(event);
   }

}

puis enregistrez cet écouteur dans votre web.xml comme ceci:

<listener>
    <listener-class>com.examples.MyHttpSessionEventPublisher</listener-class>
 </listener>
3
Ravi