Выход из режима ожидания/сеанса ожидания с помощью spring безопасности
Я использую 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 и сделать то же самое в тайм-ауте сеанса.
Существует ли аналогичный способ безопасности spring, так что, когда spring обнаруживает, что сеанс имеет таймаут, я могу подключиться к нему, получить доступ к аутентификации и получить оттуда UserDetails и выполнить очистку.
Ответы
Ответ 1
У меня есть более простое решение. Это работает как для выхода из системы, так и для сеанса.
@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>
Ответ 2
Хорошо, у меня есть решение, работающее, оно не так хорошо, как хотелось бы, но оно приводит меня к результату.
Я создаю 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 и уничтожаю, я получаю UserDetails через sessionRegistry.getSessionInfo(sessionId)
Теперь у меня есть spring beans, который мне нужно сделать для очистки сеанса и пользователя, для которого тайм-аут сеанса.
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);
}
Ответ 3
Вы можете использовать SimpleRedirectInvalidSessionStrategy для перенаправления на URL-адрес, когда SessionIDagementFilter обнаруживает недействительный запрошенный сеанс.
Пример 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 и Richfaces 4 перенаправляете на страницу входа в сеансовый тайм-аут для ajax-запросов о том, как обращаться с запросами Ajax.
ОБНОВЛЕНИЕ. В таком случае вы можете расширить 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>