2016-06-28 375 views
1

我試圖在HTTP會話銷燬時記錄消息。 我在這個Web應用程序中使用Spring Boot,Spring Security和Tomcat 8(嵌入式)。HttpSessionListener.sessionDestroyed()方法在會話超時期間被調用兩次

在會話超時期間,sessionDestroyed()方法被調用2次,所以我的消息被記錄了兩次。

我在兩次調用期間都檢查了會話ID和會話ID是SAME

這是我的代碼看起來像......

import org.springframework.security.core.session.SessionRegistry; 

...

 @Component 
     public class MySessionListener implements javax.servlet.http.HttpSessionListener, ApplicationContextAware { 
      @Autowired(required = false) 
      SessionRegistry sessionRegistry; 

和sessionDestroyed()如下。

@Override 
    public void sessionDestroyed(HttpSessionEvent se) { 
     HttpSession session = se.getSession(); 

     SecurityContextImpl springSecurityContext = (SecurityContextImpl)session.getAttribute("SPRING_SECURITY_CONTEXT"); 
     if(springSecurityContext!=null){ 
      Authentication authentication = springSecurityContext.getAuthentication(); 
      LdapUserDetails userDetails = (LdapUserDetailsImpl)authentication.getPrincipal(); 

      WebAuthenticationDetails WebAuthenticationDetails = (WebAuthenticationDetails)authentication.getDetails(); 
      String userIp = WebAuthenticationDetails.getRemoteAddress(); 

      Log.info(userDetails.getUsername(),userIp,timestamp,"timeout or logout","session destroyed"); 

     } 

     sessionRegistry.removeSessionInformation(se.getSession().getId()); 
     logger.info("Due to timeout/logout Session is Destroyed : Session ID is..." + session.getId()); 

    } 

任何幫助將不勝感激...

注:我注意到這個問題是一個缺陷的Tomcat 5,我不認爲缺陷是仍然在Tomcat中8不固定。

參考:https://bz.apache.org/bugzilla/show_bug.cgi?id=25600

回答

0

這不是Tomcat的錯誤。這是一個特定於我的應用程序的錯誤。

我在我的應用程序中找到了下面的代碼。

@Override 
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
    if (applicationContext instanceof WebApplicationContext) { 
     ((WebApplicationContext) applicationContext).getServletContext().addListener(this); 
    } else { 
     //Either throw an exception or fail gracefully, up to you 
     throw new RuntimeException("Must be inside a web application context"); 
    } 
} 

在Servlet上下文中添加當前監聽器。

getServletContext().addListener(this); 

由於春天已經加入這個監聽器(MySessionListener)成Servlet上下文,添加的偵聽含鉛進入第二sessionDestroyed()由Tomcat的org.apache.catalina.session.StandardSession類方法調用中的第二次。

Tomcat的源代碼僅供參考。

package org.apache.catalina.session; 

public class StandardSession implements HttpSession, Session, Serializable { 

.... 

public void expire(boolean notify) { 

..... 

..... 

Object listeners[] = context.getApplicationLifecycleListeners(); 
        if (listeners != null && listeners.length > 0) { 
         HttpSessionEvent event = 
          new HttpSessionEvent(getSession()); 
         for (int i = 0; i < listeners.length; i++) { 
          int j = (listeners.length - 1) - i; 
          if (!(listeners[j] instanceof HttpSessionListener)) 
           continue; 
          HttpSessionListener listener = 
           (HttpSessionListener) listeners[j]; 
          try { 
           context.fireContainerEvent("beforeSessionDestroyed", 
             listener); 
           listener.sessionDestroyed(event); 
           context.fireContainerEvent("afterSessionDestroyed", 
             listener); 
          } 

.... 
.... 

從上面的Tomcat源代碼兩者..

所以,聽衆[]包含MySessionListener的重複條目。

Object listeners[] = context.getApplicationLifecycleListeners();