Question

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.

Was it helpful?

Solution

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.

  • If you could gently prod your user base to log out all the time as good practice (although not a practical solution)
  • You could do may be body on load and check if the user is leaving your domain or used the windows close button to close the window and fire a session invalidate to capture the 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.

OTHER TIPS

Maybe you are looking for something like this:

Utility to track the current users on your site, and where they've been in detail. This allows you to track 'click streams' or 'traffic paths' across your site.

http://www.quartzscheduler.org/clickstream/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top