Friday, January 20, 2012

How to Configure Different Session Backends in Webapp2

In webapp2, sessions by default is stored in cookies.
A documentation about it can be found here:  http://webapp-improved.appspot.com/api/webapp2_extras/sessions.html
A problem I'm encountering when storing session  information in cookies, is that there seem to be a size limit of the amount of data you can store in a cookie. What happens then, is I lost my session information, and the data that I wanted to save the session is not being saved properly.
Luckily, webapp2 allows us to save sessions in two other forms: memcache and datastore (using ndb).
This is great. So then I tried to change the session configuration to have it stored in datastore, and see if it will solve my problem with large data size.

In this post I will guide you step by step on how to configure your webapp2 application to use the datastore as the session backend.

First, let's start from the top of the documentation on how to set up sessions in webapp2 using the default cookie backend:

You will create a BaseHandler and a dispatch method that creates the session store.
import webapp2
from webapp2_extras import sessions
class BaseHandler(webapp2.RequestHandler):
    def dispatch(self):
        # Get a session store for this request.
        self.session_store = sessions.get_store(request=self.request)

        try:
            # Dispatch the request.
            webapp2.RequestHandler.dispatch(self)
        finally:
            # Save all sessions.
            self.session_store.save_sessions(self.response)

    @webapp2.cached_property
    def session(self):
        # Returns a session using the default cookie key.
        return self.session_store.get_session()
You will also need to create a configuration dict to be pass in to your app that defines the session secret key.
config = {}
config['webapp2_extras.sessions'] = {
    'secret_key': 'my-super-secret-key',
}

app = webapp2.WSGIApplication([
    ('/', HomeHandler),
], config=config)
 When these has been set up you can start using your sessions as follows:

# To set a value:
self.session['foo'] = 'bar'

# To get a value:
foo = self.session.get('foo')

Now, we want to use the datastore as the session backend instead of the cookie.
We'll have to modify the configuration dictionary, adding the backends dictionary :
config['webapp2_extras.sessions'] = {
    'secret_key': 'my-super-secret-key',
    'backends': {'datastore': 'webapp2_extras.appengine.sessions_ndb.DatastoreSessionFactory',
                 'memcache': 'webapp2_extras.appengine.sessions_memcache.MemcacheSessionFactory',
                 'securecookie': 'webapp2_extras.sessions.SecureCookieSessionFactory' 
}

Next, we need to modify the session provider, specifying the backend that you wanted:
@webapp2.cached_property
def session(self):
    # Returns a session using the datastore backend.
    return self.session_store.get_session(backend='datastore')

And that's all you need to do! Now whenever you save a session, you will see a new Session entity in your AppEngine datastore. 


After storing my sessions in the datatsore instead of cookie, my problem with sessions with large amount of data was resolved. So indeed there was some kind of limit when storing your session data in cookies.


I would recommend using the datastore or memcache to store your session for a few reasons.
1. If you have sensitive information to be stored, (e.g. email addresses, phone number), it will be more secure to store it in datastore than the browser's cookie.
2. Cookie is set on domain level. Depends on how your app is set up, you could encounter session issues when navigating among different domains.
3. The most important point. In webapp2, cookie expiry is set using the max-age parameter, and this parameter is not supported in IE browsers. So if you ever want to persist the session even after browser is closed, it will just not work in IE. And since IE is still one of the major browsers nowadays, you really should care about it.

6 comments:

  1. Thanks. I can see the datastore sessions, but I also see a session cookie when using datastore session?

    ReplyDelete
  2. Why all the tutorial never mention how to destroy session?

    ReplyDelete
    Replies
    1. to destroy a session check this link http://stackoverflow.com/a/12026815/2541442

      Delete
  3. can you elaborate on how can I get
    # To set a value:
    self.session['foo'] = 'bar'

    # To get a value:
    foo = self.session.get('foo')
    How can I set a value ---> self.session['foo'] = 'bar' the dict is auto generated or do I need to make a dict, I didn't try the code as I'm confused with the dict part I mentioned above. I would assume that the DICT is auto generated by this step:
    config = {}
    config['webapp2_extras.sessions'] = {
    'secret_key': 'my-super-secret-key',
    }
    is this right?

    ReplyDelete
    Replies
    1. nevermind I did tried the code with the default GAE Hello world template here's the gist for reference: https://gist.github.com/simbha/6880776

      Delete