Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How to set sessionid cookie for AnonymousUser without using SESSION_SAVE_EVERY_REQUEST

I am attempting to track AnonymousUsers to figure out when they first come to the site, and when they then register to the website.

To do so, I created a middleware with the relevant functionality, but this initially assumed that each AnonymousUsers already had a session associated with it (i.e. sessionid cookie will be set in first response & associated session is already created in django_session). Note: session app & middleware are present

It seems that this is not the case, as looking at the session middleware, when an AnonymousUser first comes on the site, the session is never modified (Users do, since '_auth_user_id' and '_auth_user_backend' are set), and so is never created:

SessionMiddleware.process_response

def process_response(self, request, response):
    """
    If request.session was modified, or if the configuration is to save the
    session every time, save the changes and set a session cookie.
    """
    try:
        accessed = request.session.accessed
        modified = request.session.modified
    except AttributeError:
        pass
    else:
        if accessed:
            patch_vary_headers(response, ('Cookie',))
        if modified or settings.SESSION_SAVE_EVERY_REQUEST:
            if request.session.get_expire_at_browser_close():
                max_age = None
                expires = None
            else:
                max_age = request.session.get_expiry_age()
                expires_time = time.time() + max_age
                expires = cookie_date(expires_time)
            # Save the session data and refresh the client cookie.
            request.session.save()
            response.set_cookie(settings.SESSION_COOKIE_NAME,
                    request.session.session_key, max_age=max_age,
                    expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
                    path=settings.SESSION_COOKIE_PATH,
                    secure=settings.SESSION_COOKIE_SECURE or None,
                    httponly=settings.SESSION_COOKIE_HTTPONLY or None)
    return response

Attempt 1

To try and overcome this, in my Middleware, which is placed below the Session Middleware, I would force a save() on the session to create it:

if hasattr(request, 'session') and not request.session.session_key:
    request.session.save()

This would provide the session_key, but unfortunately when SessionMiddleware.process_response is called, request.session.modified is still equal to False, and so the sessionid cookie is not set...


Attempt 2

One way to do this seems to modify the session, in an arbitrary way, to ensure that request.session.modified == True, in the SessionMiddleware.process_response:

if hasattr(request, 'session') and not request.session.session_key:
    request.session.save()
    request.session['some_variable'] = True

This seems to fix my problem, without resorting to SESSION_SAVE_EVERY_REQUEST, which would be an overkill, but yet it does not seem quite right....


Question

How to make sure the session is created for an AnonymousUser with no previous visit, without explicitly modifying the session, or having SESSION_SAVE_EVERY_REQUEST=True?

Thanks for your help!

like image 698
YacineAzmi Avatar asked Feb 19 '13 04:02

YacineAzmi


1 Answers

Even explicitly modifying the session can fail (eg assigning an attribute to a session attribute).

You need to explicitly set session.modified to true

if hasattr(request, 'session') and not request.session.session_key:
    request.session.save()
    request.session.modified = True

Have a look at what the docs say on when sessions are saved.

like image 129
Aidan Ewen Avatar answered Sep 19 '22 14:09

Aidan Ewen