I am developing a webapp that uses Spring Security as security layer.
One important feature for us is to know which user is accessing the application, and how many time they are spending on it.
I'm not sure how to deal with it. Is there some other framework that deals with this kind of usage statistics?
Is there some way to use Spring Security itself to deal with it?
// I'm reading more about Spring Security and it seems that its filters can help me. Any progress will be shared here.
Spring Security Session Timeout In the case of Tomcat we can set the session timeout by configuring the maxInactiveInterval attribute on the manager element in server. xml or using the session-timeout element in web. xml. Note that the first option will affect every app that's deployed to the Tomcat instance.
Solution. Review the existing Spring Security's authentication class, the “locked” feature is already implemented. To enable the limit login attempts, you need to set the UserDetails. isAccountNonLocked to false.
I think one of the solutions I can think of is using a HttpSessionListener, If you implement a Session listener you could capture the time as and when a new user session is created and destroyed, You could leverage your spring security context holder to get a hold of the uniquename/userid of the logged in user
I am thinking some thing like this
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
}
}
That being said there are few down sides to this approach, If the HTTP Session never gets invalidated then you will end up with some sessions with no end time.
UPDATE
You are right I think you could use spring application event mechanism, to do that add this to your web.xml, This listener publishes HTTP session events other wise you won't be able to access session events even if you implement ApplicationListener
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
Now add a new class that implements 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 () );
}
}
}
There is another event if you would like to capture logout by itself, You can implement LogoutHandler that gives you access to logut event.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With