私が考えることができる解決策の 1 つは、HttpSessionListener を使用することだと思います。セッション リスナーを実装すると、新しいユーザー セッションが作成および破棄されたときの時間をキャプチャできます。Spring セキュリティ コンテキスト ホルダーを活用して、保持することができます。ログインしたユーザーの一意の名前/ユーザー ID
こんなことを考えている
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セッションが無効にならない場合、終了時間のないいくつかのセッションが発生します.
- 良い習慣として、常にログアウトするようにユーザーベースをそっと促すことができれば (実用的な解決策ではありませんが)
- body on load を実行して、ユーザーがドメインを離れているかどうか、またはウィンドウの閉じるボタンを使用してウィンドウを閉じ、セッションの無効化を開始して終了時間をキャプチャするかどうかを確認することができます
アップデート
そうです、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 () );
}
}
}
ログアウトを単独でキャプチャしたい場合は、別のイベントがあります。logut イベントへのアクセスを提供する LogoutHandler を実装できます。