Close

Servlet - Keep Session Alive for Active User and Auto Redirect To Login Page On Session Timeout

[Last Updated: Jun 27, 2018]

In the last example we saw how to forward to login page on session expiration. The problem with that approach is that the session might get expired on server while user is still actively working on the client. The client will only know about session timeout on making next server request.

Following example shows how to keep extending session timeout while user is still active on the client. We are going to use JQuery on the client to monitor user activity and to send Ajax requests to the server to extend the session. If user becomes idle for a certain time period (say 2 mins) then send logout request to the server and redirect to login page.

Example

Servlets

@WebServlet(name = "securedServlet", urlPatterns = {"/"})
public class MySecuredServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req,
                       HttpServletResponse resp) throws ServletException, IOException {

      Principal principal = req.getUserPrincipal();
      if (principal == null || !req.isUserInRole("employee")) {
          LoginHandlerServlet.forwardToLogin(req, resp, null);
          return;
      }

      req.setAttribute("user", req.getRemoteUser());
      req.getRequestDispatcher("/employee-page.jsp")
         .forward(req, resp);
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
      doGet(req, resp);
  }
}
@WebServlet(name = "loginServlet", urlPatterns = {"/loginHandler"})
public class LoginHandlerServlet extends HttpServlet {
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {

      String theUser = req.getParameter("theUser");
      String thePassword = req.getParameter("thePassword");
      try {
          req.login(theUser, thePassword);
      } catch (ServletException e) {
          System.out.println(e.getMessage());
          forwardToLogin(req, resp, "Error: " + e.getMessage());
          return;
      }
      boolean loggedIn = req.getUserPrincipal() != null && req.isUserInRole("employee");
      if (loggedIn) {
          resp.sendRedirect("/");
      } else {
          forwardToLogin(req, resp, "Login failed.");
      }
  }

  public static void forwardToLogin(HttpServletRequest req, HttpServletResponse resp,
                                    String errorMessage)
          throws ServletException, IOException {
      req.setAttribute("errorMsg", errorMessage);
      req.getRequestDispatcher("/login.jsp")
         .forward(req, resp);
  }
}
@WebServlet(name = "logoutServlet", urlPatterns = {"/logout"})
public class LogoutServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws ServletException, IOException {
      System.out.println("logging out");
      req.logout();
      Principal principal = req.getUserPrincipal();
      if (principal != null) {
          throw new RuntimeException("Cannot log out the user");
      }

      HttpSession session = req.getSession(false);
      if (session != null) {
          //invalidate session specially if we have added some user specific info
          session.invalidate();
      }

      Object msg = req.getParameter("msg");
      if ("onTimeOut".equals(msg)) {
          LoginHandlerServlet.forwardToLogin(req, resp, "Session timeout.");
          return;
      }

      resp.sendRedirect("/");
  }
}
@WebServlet(name = "refreshServlet", urlPatterns = {"/refreshSession"})
public class RefreshSessionServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req,
                       HttpServletResponse resp) {

      System.out.println("refreshing session");
      if(!req.isUserInRole("employee")){
          System.err.println("User logged out already, "
                  + "set higher setMaxInactiveInterval() ");
          resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
          return;
      }
      HttpSession session = req.getSession();
      if (session == null) {
          System.err.println("cannot renew session");
      }
  }
}

Implementing HttpSessionListener

We are implementing HttpSessionListener to set a custom session timeout.

@WebListener
public class MySessionListener implements HttpSessionListener {
  @Override
  public void sessionCreated(HttpSessionEvent se) {
      System.out.println("-- HttpSessionListener#sessionCreated invoked --");
      HttpSession session = se.getSession();
      System.out.println("session id: " + session.getId());
      session.setMaxInactiveInterval(120);//in seconds
  }

  @Override
  public void sessionDestroyed(HttpSessionEvent se) {
      System.out.println("-- HttpSessionListener#sessionDestroyed invoked --");
  }
}

JSP pages

src/main/webapp/login.jsp

<html>
<body>
<div style="color:red">
    <%
     Object msg = request.getAttribute("errorMsg");
        if(msg != null ){
           out.println(msg);
        }
     %>
</div>
<form action="/loginHandler" method="post">
    <table>
        <tr>
            <td> User:</td>
            <td><input type="text" name="theUser"/></td>
        </tr>
        <tr>
            <td> Password:</td>
            <td><input type="password" name="thePassword"/></td>
        </tr>
    </table>
    <input type="submit" value="Submit"/>
</form>
</body>
</html>

src/main/webapp/employee-page.jsp

<html>
<body>
<head>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 <script>
    var lastActiveTime = new Date().getTime();
    $(document).ready(function() {
        $('body').bind('click mousemove keypress scroll resize', function() {
           lastActiveTime = new Date().getTime();
           });
           setInterval(checkIdleTime, 30000); // 30 sec
    });

     function checkIdleTime(){
     var diff = new Date().getTime() - lastActiveTime;
           if( diff > 120000){//2 min of inactivity
            window.location.href ="/logout?msg=onTimeOut"
           }else{
               $.ajax({url: '/refreshSession', error: function(data, status, xhr){
                    alert("cannot refresh session on server: "+xhr);
                    window.location.reload();}
                  });
           }
    }
  </script>
</head>
<h2>Employee page</h2>
<div>User: <%= request.getAttribute("user")%> </div>
<br/>
<a href='/logout'>Logout</a>
</body>
</html>

Adding tomcat-users.xml

Since we are using embedded tomcat for our demo, we are going to add tomcat-users.xml with authentication info:

src/main/webapp/config/tomcat-users.xml

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
    <role rolename="employee"/>
    <user username="joe" password="123" roles="employee"/>
</tomcat-users>

Specifying tomcat-user.xml location in pom.xml:

<plugin>
  <groupId>org.apache.tomcat.maven</groupId>
  <artifactId>tomcat7-maven-plugin</artifactId>
  <version>2.2</version>
  <configuration>
   <path>/</path>
   <tomcatUsers>src/main/webapp/config/tomcat-users.xml</tomcatUsers>
  </configuration>
 </plugin>

Running

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

Output

Accessing http://localhost:8080/ and entering valid user name and password:

On submitting the form:

Session will be extending on the server side at 30 seconds rate given that user is active on the page. If user does not do anything (i.e. use mouse, key press, scrolling etc) for 2 mins then user will be logged out automatically and the page will be redirected to login page:

Example Project

Dependencies and Technologies Used:

  • javax.servlet-api 3.1.0 Java Servlet API
  • JDK 10
  • Maven 3.5.4

Servlet - Auto redirect using JQuery Select All Download
  • servlet-session-timeout-jquery-auto-logout
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • webapp
          • config
          • employee-page.jsp

    See Also