2012-08-07 119 views
31

我使用的是spring/spring-security 3.1,並且希望在用戶註銷時(或者如果會話超時)採取一些操作。我設法完成註銷操作,但會話超時,我無法使其工作。註銷/會話超時捕捉彈簧安全

在web.xml中,我只指定了ContextLoaderListener(這可能是問題嗎?),當然還有DelegatingFilterProxy。

我使用像這樣的自動配置。

<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> 

當用戶點擊註銷的註銷處理程序被調用,這將使到數據庫幾個電話。

但是,我該如何處理會話超時?

處理它的一種方法是在用戶登錄時將用戶名注入會話中,然後使用普通的httpsessionlistener並在會話超時時執行相同的操作。

是否有類似的方式與春季安全,所以當春天發現會話超時,我可以掛在那裏,訪問身份驗證,並從那裏得到UserDetails並進行清理。

回答

51

我有一個更簡單的解決方案。這適用於註銷和會話超時。

@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> 
+1

從我的pov這是更好的解決方案。我強烈建議使用這個,就像我一樣。 Thx約翰。順便說一句:這也處理「正常」登出! – 2014-02-07 12:53:23

+0

在使用'Spring Security'的時候,會話中提到的是,它等同於HTTPSession還是Spring安全會話?另一方面,新的'春季會議'組件似乎提供了一個解決方案http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository/sessiondestroyedevent – yathirigan 2015-03-11 04:59:27

+5

@yathirigan不確定你的意思是「春季安全會議」。 Spring Security使用HTTP會話,所以基本上它是一樣的。 – John29 2015-03-11 14:15:40

3

當SessionManagementFilter檢測到無效的請求會話時,您可以使用SimpleRedirectInvalidSessionStrategy重定向到URL。

樣品的applicationContext會是這樣的:

<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"/> 

如果使用JSF,同時參考JSF 2, Spring Security 3.x and Richfaces 4 redirect to login page on session time out for ajax requests如何處理Ajax請求爲好。

UPDATE:在這種情況下,你可以擴展HttpSessionEventPublisher和監聽sessionDestroyed這樣的活動:

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); 
    } 

} 

,然後在你的web.xml這樣註冊這個監聽器:

<listener> 
    <listener-class>com.examples.MyHttpSessionEventPublisher</listener-class> 
</listener> 
+0

感謝您的建議,但我認爲這不會解決問題。我需要捕捉會話超時,我不能等待用戶發出請求(他/她有時不會這樣做,例如關閉瀏覽器)。我需要做一些釋放用戶可能已經鎖定的鎖,這可能會鎖定其他人。 不,不使用JSF,只是彈簧和速度。 – Perre 2012-08-08 09:48:32

+0

更新了答案! – Ravi 2012-08-08 14:42:05

+0

有沒有辦法獲得認證對象。我試過了,但通過SecurityContextHolder.getContext()獲取它。getAuthentication()返回null。我需要在超時之前將會話綁定到會話。我的意思是,這對我來說看起來像HttpSession過期事件。 如何從此事件中獲取Authenticated UserDetails對象? – Perre 2012-08-08 21:01:11

6

好吧,我有一個解決方案的工作,這不是我想要的,但它讓我想到了結果。

我創建了一個bean,我可以從中獲取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(); 
} 
} 

我實現HttpSessionEventPublisher和破壞,我通過sessionRegistry.getSessionInfo(階段ID)得到的UserDetails

現在我有春豆,我需要做的會話的清理和對他們來說,用戶會話超時。

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); 
}