Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
372 views
in Technique[技术] by (71.8m points)

servlets - Session or cookie confusion

I've seen in some websites that user signed in into their accounts and then closed the browser.

After closed and re-opened the browser and their accounts are still signed in.

But some websites, cannot do like that.

I'm confused that it's considered session or cookie?

If I want my website to be signed in like that, do I have to set session.setMaxInactiveInterval() or cookie.setMaxAge()?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

* This answer has serious flaws, see comments. *


Your question is about session tracking.

[PART 1] : SESSION OBJECT

HTTP-request are processed separately, so in order to keep information between each request (for instance, information about the user), a session object has to be created on server-side.

Some websites doesn't need a session at all. A website where users can't modify any content won't have to manage a session (for instance, an online CV). You won't need any cookie or session on such a website.

Create a session :

In a servlet, use the method request.getSession(true) from the HttpServletRequest object to create a new HttpSession object. Note that if you use request.getSession(false), null will be returned if the session has not already been created. Look at this answer for more details.

Set / Get attributes :

The purpose of a session is to keep information on server-side between each request. For instance, keeping the user's name :

session.setAttribute("name","MAGLEFF");
// Cast
String name = (String) session.getAttribute("name");

Destroy a session :

A session will be automatically destroyed if kept inactive too much time. Look at this answer for more details. But you can manually force the session to be destroyed, in the case of a logout action for example :

HttpSession session = request.getSession(true); 
session.invalidate();

[PART 2] : So... join the dark side, we have COOKIES ?

Here comes the cookies.

JSESSIONID :

A JSESSIONID cookie is created on the user's computer each time a session is created with request.getSession(). Why? Because each session created on server side has an ID. You can't access another user's session, unless you don't have the right ID. This ID is kept in JSESSIONID cookie, and allow the user to find his information. Look at this answer for more details !

When does a JSESSIONID get deleted ?

JSESSIONID doesn't have an expiration date : it's a session cookie. As all session cookies, it will be deleted when the browser is closed. If you use the basic JSESSIONID mechanism, then the session will become unreachable after you close and re-open the browser, because the JSESSIONID cookie is deleted.

Note that the session is unreachable by the client, but is still running on server-side. Setting a MaxInactiveInterval allows the server to automatically invalidate the session when it has been inactive for too long.

Evil destruction of JSESSIONID

Just for fun, one day I found this code on a project. It was used to invalidate the session by deleting the JSESSIONID cookie with javascript :

<SCRIPT language="JavaScript" type="text/javascript">

    function delete_cookie( check_name ) {
        // first we'll split this cookie up into name/value pairs
        // note: document.cookie only returns name=value, not the other components
        var a_all_cookies = document.cookie.split( ';' );
        var a_temp_cookie = '';
        var cookie_name = '';
        var cookie_value = '';
        var b_cookie_found = false; // set boolean t/f default f
        // var check_name = 'JSESSIONID';
        var path = null;

        for ( i = 0; i < a_all_cookies.length; i++ )
        {
            // now we'll split apart each name=value pair
            a_temp_cookie = a_all_cookies[i].split( '=' );
            // and trim left/right whitespace while we're at it
            cookie_name = a_temp_cookie[0].replace(/^s+|s+$/g, '');
            // alert (cookie_name);

            // if the extracted name matches passed check_name
            if ( cookie_name.indexOf(check_name) > -1 )
            {
                b_cookie_found = true;
                // we need to handle case where cookie has no value but exists (no = sign, that is):
                if ( a_temp_cookie.length > 1 )
                {
                    cookie_value = unescape( a_temp_cookie[1].replace(/^s+|s+$/g, '') );
                    document.cookie = cookie_name + "=" + cookie_value +
                    ";path=/" +
                    ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
                    // alert("cookie deleted " + cookie_name);
                }
            }
            a_temp_cookie = null;
            cookie_name = '';
        }
        return true;
    }
    // DESTROY
    delete_cookie("JSESSIONID");

</SCRIPT>

Give another look to this answer. With JavaScript, JSESSIONID can be read, modified, have it's session lost or hijacked.

[PART 3] : KEEPING A SESSION AFTER CLOSING YOUR BROWSER

After closed and re-opened the browser and their accounts are still signed in. But some websites, cannot do like that. I'm confused that it's considered session or cookie??

It's cookie.

We saw that when the JSESSIONID session cookie has been deleted by the web browser, the session object on server-side is lost. There is no way to access it again without the right ID.

If I want my website to be signed in like that, do I have to set session.setMaxInactiveInterval() or cookie.setMaxAge()?

We also saw that session.setMaxInactiveInterval() was to prevent from running a lost session indefinitely. JSESSIONID cookie cookie.setMaxAge() won't get us anywhere either.

Use a persistent cookie with the session Id :

I came to this solution after reading the following topics :

The main idea is to register the user's session in a Map, put into the servlet context. Each time a session is created, it is added to the Map with the JSESSIONID value for key; A persistent cookie is also created to memorize the JSESSIONID value, in order to find the session after the JSESSIONID cookie has been destroyed.

When you close the web browser, JSESSIONID is destroyed. But all the HttpSession objects adress have been kept into a Map on server-side, and you can access the right session with the value saved into the persistent cookie.

First, add two listeners in your web.xml deployment descriptor.

<listener>
    <listener-class>
        fr.hbonjour.strutsapp.listeners.CustomServletContextListener
    </listener-class>
</listener>

<listener>
    <listener-class>
        fr.hbonjour.strutsapp.listeners.CustomHttpSessionListener
    </listener-class>
</listener>

The CustomServletContextListener creates a map at context initialization. This map will register all the sessions created by the user on this application.

/**
 * Instanciates a HashMap for holding references to session objects, and
 * binds it to context scope.
 * Also instanciates the mock database (UserDB) and binds it to 
 * context scope.
 * @author Ben Souther; [email protected]
 * @since Sun May  8 18:57:10 EDT 2005
 */
public class CustomServletContextListener implements ServletContextListener{

    public void contextInitialized(ServletContextEvent event){
        ServletContext context = event.getServletContext();

        //
        // instanciate a map to store references to all the active
        // sessions and bind it to context scope.
        //
        HashMap activeUsers = new HashMap();
        context.setAttribute("activeUsers", activeUsers);
    }

    /**
     * Needed for the ServletContextListener interface.
     */
    public void contextDestroyed(ServletContextEvent event){
        // To overcome the problem with losing the session references
        // during server restarts, put code here to serialize the
        // activeUsers HashMap.  Then put code in the contextInitialized
        // method that reads and reloads it if it exists...
    }
}

The CustomHttpSessionListener will put the session into the activeUsers map when it is created.

/**
 * Listens for session events and adds or removes references to 
 * to the context scoped HashMap accordingly.
 * @author Ben Souther; [email protected]
 * @since Sun May  8 18:57:10 EDT 2005
 */
public class CustomHttpSessionListener implements HttpSessionListener{

    public void init(ServletConfig config){
    }

    /**
     * Adds sessions to the context scoped HashMap when they begin.
     */
    public void sessionCreated(HttpSessionEvent event){
        HttpSession    session = event.getSession();
        ServletContext context = session.getServletContext();
        HashMap<String, HttpSession> activeUsers =  (HashMap<String, HttpSession>) context.getAttribute("activeUsers");

        activeUsers.put(session.getId(), session);
        context.setAttribute("activeUsers", activeUsers);
    }

    /**
     * Removes sessions from the context scoped HashMap when they expire
     * or are invalidated.
     */
    public void sessionDestroyed(HttpSessionEvent event){
        HttpSession    session = event.getSession();
        ServletContext context = session.getServletContext();
        HashMap<String, HttpSession> activeUsers = (HashMap<String, HttpSession>)context.getAttribute("activeUsers");
        activeUsers.remove(session.getId());
    }

}

Use a basic form to test a user authentification by name/password. This login.jsp form is meant for test only.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
        <title><bean:message key="formulaire1Title" /></title>
    </head>
    <body>
        <form action="login.go" method="get">
            <input type="text" name="username" />
            <input type="password" name="password" />
            <input type="submit" />
        </form>
    </body>
</html>

There we go. This java servlet is forwarding to a login page when the user is not in session, and to another page when he is. It is only meant for testing the persistent session!

public class Servlet2 extends AbstractServlet {

    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...