我正在使用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>
当用户单击logout时会调用logout处理程序,这会对数据库进行一些调用。
但是如何处理会话超时???
处理它的一种方法是在用户登录时将用户名注入会话,然后使用普通的httpsessionlistener并在会话超时时执行相同的操作。
Spring安全性是否有类似的方式,所以当spring发现会话超时时,我可以在那里挂钩,访问Authentication并从那里获取UserDetails并进行清理。
答案 0 :(得分:55)
我有一个更简单的解决方案。这适用于注销和会话超时。
@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 :(得分:7)
好的,我找到了一个解决方案,但它并不像我想的那么好,但它让我得到了结果。
我创建了一个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并在destroy上,我通过sessionRegistry.getSessionInfo(sessionId)获取UserDetails
现在我有了我需要清理会话的春天bean以及会话超时的用户。
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);
}
答案 2 :(得分: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>