Disable multiple logins for same user - Servlets and Sessions

There are many approaches including the database flag for a user to know whether a user is logged in currently or not. Database solution takes lot of work and amount of time to implement and has many problems including browser close should also log-out for the user does not wait so many minutes before sessions get invalidated automatically. HttpSessionListener must also be implemented in the database solution, hence I will strongly discourage the use of this approach, which involves re-inventing the wheel again and again because every developer has to do it on his own for his application. 


HttpSessionBindingListener

There are two ways users can be restricted to login from multiple sessions, either previous session of user be removed, or new session of user be disallowed. In both approaches I would recommend using HttpSessionBindingListener. Implementing this interface requires providing implementation for boolean equals(Object other),int hashCode(), void valueBound(HttpSessionBindingEvent event) and void valueUnbound(HttpSessionBindingEvent event).

public class LoginDto implements HttpSessionBindingListener {
  private String accountId
  private boolean alreadyLoggedIn;
  //setters and getters of all your User dto including accountId...

  @Override
  public boolean equals(Object other) {
    return (other instanceof LoginDto) && (getAccountId() != null) ? 
   getAccountId().equals(((LoginDto) other).getAccountId()) : (other == this);
  }
  
  @Override
  public int hashCode() {
    return (getAccountId() != null) ? 
   (this.getClass().hashCode() + getAccountId().hashCode()) : super.hashCode();
  }
  
  @Override
  public void valueBound(HttpSessionBindingEvent event){
    HttpSession oldSession = logins.get(this);
    if (oldSession != null) {
      alreadyLoggedIn = true;
    } else {
      logins.put(this, event.getSession());
    }

    //Note: you can comment above code and remove comments from below code. removing comments from 
//below code will remove old session of user and let the user log-in from new session.

    //HttpSession session = logins.remove(this);
    //if (session != null) {
    //  session.invalidate();
   //}
   //logins.put(this, event.getSession());  
  }
  
  @Override
  public void valueUnbound(HttpSessionBindingEvent event) {
    logins.remove(this);
  }
  
}//end of class LoginDto

 You do not need to do anything else except storing a LoginDto in session when a user logs in, or removing it on session timeout. Http Session Binding Listener should automatically invoke valueBound and valueUnbound methods whenever LoginDto is bound to session, not to mention, browser's close or in cases when users leave unexpectedly.

Example servlet code

if(//user is valid and validated from database etc...) {
    session.setAttribute("UserContext", dto); //this will invoke valueBound method of LoginDto.
    if(dto.isAlreadyLoggedIn()){
      session.removeAttribute("UserContext"); //this will invoke valueUnbound method of LoginDto
      throw new MyCustomException("You are already logged in from a different session. Please logout first.");
    }
}else {
    session.setAttribute("UserContext", null);
}

Comments