Я думаю, что одним из решений, которое я могу придумать, является использование HttpSessionListener. Если вы реализуете слушатель Session, вы можете фиксировать время, когда и когда создается и уничтожается новый пользовательский сеанс, вы можете использовать свой весенний держатель контекста безопасности, чтобы захватить уникальное имя / ИД пользователя вошедшего в систему пользователя
Я думаю, что-то вроде этого
public class SesssionListenerImpl implements HttpSessionListener
{
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent)
{
String uniqueName = SecurityContextHolder.getContext().getAuthentication().getName();
String sessionId = httpSessionEvent.getSession().getId();
long beginTimeInSeconds = System.currentTimeMillis()/1000;
//create a record and persist to data base with sessionId, uniquename, sessionBeginTime
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent)
{
SecurityContextHolder.getContext().getAuthentication().getPrincipal();
httpSessionEvent.getSession().getId();
long endTime = System.currentTimeMillis()/1000;
//load the record based on sessionId
//update the record with sessionEndTime
}
}
При этом есть несколько недостатков в этом подходе. Если сеанс HTTP никогда не будет признан недействительным, вы получите несколько сеансов без времени окончания.
- Если бы вы могли аккуратно подтолкнуть свою пользовательскую базу, чтобы все время выходить из системы, как хорошая практика (хотя это и не практическое решение)
- Вы можете сделать это при загрузке тела и проверить, покидает ли пользователь ваш домен или использует кнопку закрытия окна, чтобы закрыть окно и запустить недействительный сеанс для захвата времени окончания
UPDATE
Вы правы, я думаю, что вы могли бы использовать механизм событий приложений Spring, чтобы сделать это, добавив это в ваш web.xml. Этот слушатель публикует события сеанса HTTP, иначе вы не сможете получить доступ к событиям сеанса, даже если вы реализуете ApplicationListener.
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
Теперь добавьте новый класс, который реализует ApplicationListener
@Service
public class ApplicationSecurityListener implements ApplicationListener<ApplicationEvent>
{
@Override
public void onApplicationEvent(ApplicationEvent event)
{
if ( event instanceof AuthorizationFailureEvent )
{
AuthorizationFailureEvent authorizationFailureEvent = ( AuthorizationFailureEvent ) event;
System.out.println ( "not authorized:" + authorizationFailureEvent );
}
else if ( event instanceof AuthenticationFailureBadCredentialsEvent )
{
AuthenticationFailureBadCredentialsEvent badCredentialsEvent = ( AuthenticationFailureBadCredentialsEvent ) event;
System.out.println ( "badCredentials:" + badCredentialsEvent );
}
//login success event
else if ( event instanceof AuthenticationSuccessEvent )
{
AuthenticationSuccessEvent authenticationSuccessEvent = ( AuthenticationSuccessEvent ) event;
//this will provide user id and password but no session, get source has all the user information in security context
System.out.println ( "AuthenticationSuccessEvent:" + authenticationSuccessEvent.getSource() );
}
//this event will published if you add the HttpSessionEventPublisher to web.xml
else if ( event instanceof SessionDestroyedEvent )
{
SessionDestroyedEvent sessinEvent = ( SessionDestroyedEvent ) event;
System.out.println ( "SessionDestroyedEvent:" + sessinEvent.getId() );
//load session if it is not empty
if(sessinEvent.getSecurityContext() != null)
{
System.out.println ( "SessionDestroyedEvent:" + sessinEvent.getSecurityContext().getAuthentication().getName() );
//update the session with endTime
}
}
else
{
//System.out.println ( "undefined: " + event.getClass ().getName () );
}
}
}
Существует другое событие, если вы хотите захватить выход из системы самостоятельно. Вы можете реализовать LogoutHandler, который дает вам доступ к событию выхода из системы.