9

Shouldn't invalidating a session cause request.getSession(false) to return null? In my logout servlet I call

session.invalidate();

and in my login status filter I call

request.getSession(false);

The call to getSession(false) never returns null but all attributes associated with the session object returned are null. I currently detect if a user is logged out by searching for null attributes but this doesn't seem right.

Usman Mutawakil
  • 4,993
  • 9
  • 43
  • 80
  • 1
    There might be something else running in between (after invalidate and before getsession), which is creating the session. Are you using plain servlets or something else also (specially the one that requires session, e.g. component based frameworks like JSF can be set to save the states on server which requires session)? – Bhesh Gurung Jan 28 '13 at 07:48
  • Plain servlets no framework – Usman Mutawakil Jan 28 '13 at 08:31
  • I'm going to look around and see if I'm the culprit calling request.getSession(true) somewhere. – Usman Mutawakil Jan 28 '13 at 08:37
  • How are you navigating from `Logout` Servlet to `LoginStatus` filter, after invalidating session? – Rohit Jain Jan 28 '13 at 08:52
  • @RohitJain The logout servlet gets accessed when going to "/Logout" but the logout status filter filters every request so that if a user is logged in and goes to the homepage they see the members page instead of the login screen. It all works. I was just being picky about actually killing a session and not just stripping it's attributes, which appears to be all session.invalidate() actually does. – Usman Mutawakil Jan 29 '13 at 05:14

2 Answers2

10

I currently detect if a user is logged out by searching for null attributes

That's also the normal approach. To check if an user is logged in, you should surely not check if the servletcontainer has created the session or not. This does not represent the logged-in user at all.

On login, just put the user model object in the session scope without checking if the container has created the session for you. In other words, just use getSession() without boolean argument so that the container will autocreate if necessary, you need the session at this point anyway:

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    User user = userService.find(username, password);

    if (user != null) {
        request.getSession().setAttribute("user", user);
        response.sendRedirect(request.getContextPath() + "/home");
    } else {
        request.setAttribute("message", "Unknown login. Please retry.");
        request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
    }
}

On access filtering, just check if the session attribute representing the logged-in user is present, you only use getSession(false) here to avoid unnecessary session creation, otherwise for example searchbots would trigger session creation which is totally unnecessary:

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    HttpSession session = request.getSession(false);
    User user = (session != null) ? (User) session.getAttribute("user") : null;
    String loginURL = request.getContextPath() + "/login"; 

    if (user == null && !request.getRequestURI().equals(loginURL)) {       
        response.sendRedirect(loginURL);
    } else {
        chain.doFilter(request, response);
    }
}

On logout, make sure that you send a redirect after invalidate, because the current session is still available in the response of a forward.

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getSession().invalidate();
    response.sendRedirect(request.getContextPath() + "/login");
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • This is the exact approach I've been taking. The fact that the session object was still "valid" after invalidating it made me nervous I was doing something wrong but it looks like the gold is in the attributes so I'll stay the course. Thanks. – Usman Mutawakil Jan 29 '13 at 05:10
  • I'm guessing the redirect is a quicker method of forcing the browser to clear the cache as oppose to the approach specified here http://stackoverflow.com/questions/4194207 ? – Usman Mutawakil Jan 29 '13 at 05:25
  • Preventing the browser to cache the restricted pages solves a completely different problem than asked/answered here. If you don't disable browser cache, then the enduser may still see the restricted pages on pressing the back button. If you disable the browser cache, then the enduser will be redirected to the login page on pressing the back button. – BalusC Jan 29 '13 at 10:28
  • What is the purpose of the redirect then if your not using it to force a refresh? – Usman Mutawakil Jan 29 '13 at 20:13
  • Because, as said, the current session is still available in the response of a forward. – BalusC Jan 29 '13 at 20:14
  • @BalusC could you expand on the logic why you've decided to use sendRedirect and RequestDispatcher in the way you did it with the LoginServlet example? – e.doroskevic Dec 18 '14 at 11:39
2

for every servlet or jsp you travel you should call

request.getSession(false);

except for you first page where you create the sessionby

request.getSession(true);

if you dont call

request.getSession(false);

then the session is not carried till that page so before you call

session.invalidate();

make sure you are continuing the session to that page by calling

request.getSession(false);
  • Thanks for the response. Calling getSession(true) would never return null. The problem I have is that getSession(false) is not returning null when it should. For example, running the code I provided earlier a user can still visit pages that require getSession(false)!=null – Usman Mutawakil Jan 28 '13 at 08:34
  • you are calling "session.invalidate();" ryt ?? are you sure the page where yo call this line is having the session , if not , plz call "request.getSession(false);" line in the page , may be i m not getting your prob correctly , but after making sure this , we can get to understand – Hussain Akhtar Wahid 'Ghouri' Jan 28 '13 at 09:02
  • Yes. I always call getSession(false) except for where I want to create a session at login. I understand the concept and I am able to login and access all features that require attributes stored in my session. The problem is when I attempt to logout all that happens when invalidating a session is that all attributes are removed but the session does not go null. I thought it was my code but I think that is simply how it is. Thanks for the help anyway. – Usman Mutawakil Jan 29 '13 at 05:09