The Master Class of "Learn Spring Security" is out:
1. Introduction
In this tutorial, we are going to focus on the Spring MVC HandlerInterceptor.
More specifically, we will show a more advanced use case for using interceptors – we’ll emulate a session timeout logic by setting custom counters and tracking sessions manually.
If you want to read about the HandlerInterceptor’s basics in Spring, check out this article.
2. Maven Dependencies
In order to use Interceptors, you need to include the following section in a dependencies section of your pom.xml file:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
The latest version can be found here. This dependency only covers Spring Web so don’t forget to add spring-core and spring-context for a full (minimal) web application.
3. Custom Implementation of Session Timeouts
In this example, we will configure maximum inactive time for the users in our system. After that time, they will be logged out automatically from the application.
This logic is just a proof of concept – we can of course easily achieve the same result using session timeouts – but the result is not the point here, the usage of the interceptor is.
And so, we want to make sure that session will be invalidated if the user is not active. For example, if a user forgot to log out, the inactive time counter will prevent accessing the account by unauthorized users. In order to do that, we need to set constant for the inactive time:
private static final long MAX_INACTIVE_SESSION_TIME = 5 * 10000;
We set it to 50 seconds for testing purposes; don’t forget, it is counted in ms.
Now, we need to keep track of each session in our app, so we need to include this Spring Interface:
@Autowired private HttpSession session;
Let’s proceed with the preHandle() method.
3.1. preHandle()
In this method we will include following operations:
- setting timers to check handling time of the requests
- checking if a user is logged in (using UserInterceptor method from this article)
- automatic logging out, if the user’s inactive session time exceeds maximum allowed value
Let’s look at the implementation:
@Override public boolean preHandle( HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception { log.info("Pre handle method - check handling start time"); long startTime = System.currentTimeMillis(); request.setAttribute("executionTime", startTime); }
In this part of the code, we set the startTime of handling execution. From this moment, we will count a number of seconds to finish handling of each request. In the next part, we will provide logic for session time, only if somebody logged in during his HTTP Session:
if (UserInterceptor.isUserLogged()) { session = request.getSession(); log.info("Time since last request in this session: {} ms", System.currentTimeMillis() - request.getSession().getLastAccessedTime()); if (System.currentTimeMillis() - session.getLastAccessedTime() > MAX_INACTIVE_SESSION_TIME) { log.warn("Logging out, due to inactive session"); SecurityContextHolder.clearContext(); request.logout(); response.sendRedirect("/spring-security-rest-full/logout"); } } return true;
First, we need to get the session from the request.
Next, we do some console logging, about who is logged in, and how long has passed, since the user performs any operation in our application. We may use session.getLastAccessedTime() to obtain this information, subtract it from current time and compare with our MAX_INACTIVE_SESSION_TIME.
If time is longer than we allow, we clear the context, log out the request and then (optionally) send a redirect as a response to default logout view, which is declared in Spring Security configuration file.
To complete counters for handling time example, we also implement postHandle() method, which is described in the next subsection.
3.2. postHandle()
This method is implementation just to get information, how long it took to process the current request. As you saw in the previous code snippet, we set executionTime in Spring model. Now it’s time to use it:
@Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView model) throws Exception { log.info("Post handle method - check execution time of handling"); long startTime = (Long) request.getAttribute("executionTime"); log.info("Execution time for handling the request was: {} ms", System.currentTimeMillis() - startTime); }
The implementation is simple – we check an execution time and subtract it from a current system time. Just remember to cast the value of the model to long.
Now we can log execution time properly.
4. Config of the Interceptor
To add our newly created Interceptor into Spring configuration, we need to override addInterceptors() method inside WebConfig class that extends WebMvcConfigurerAdapter:
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SessionTimerInterceptor()); }
We may achieve the same configuration by editing our XML Spring configuration file:
<mvc:interceptors> <bean id="sessionTimerInterceptor" class="org.baeldung.web.interceptor.SessionTimerInterceptor"/> </mvc:interceptors>
Moreover, we need to add listener, in order to automate the creation of the ApplicationContext:
public class ListenerConfig implements WebApplicationInitializer { @Override public void onStartup(ServletContext sc) throws ServletException { sc.addListener(new RequestContextListener()); } }
5. Conclusion
This tutorial shows how to intercept web requests using Spring MVC’s HandlerInterceptor in order to manually do session management/timeout.
As usual, all examples and configurations are available here on GitHub.
5.1. Articles in the Series
All articles of the series:
- Introduction to Spring MVC Handler Interceptors
- Changing Spring Model Parameters with Handler Interceptor
- + the current article