Below is the session class and some examples of it's use I've come up
with. The purpose of this was to meet two goals. 1: I wanted a way to
handle sessions so I can move on to building a user auth system for my
site. I have chosen not to use the Google one supplied. 2: This is the
very first thing I've ever written in python, so it's a learning
experience.
I'm submitting this to the public domain. While you may feel free to
use it, I'm really looking for feedback on it from people more
experienced with appengine and python in general. I'm not submitting
that this is the best approach, just the best I came up with.
Two things I intend to implement into this is support for setting a
cookie path, and also handling for setting an expire time for cookies,
and then having expired data and session ids deleted. I thought I'd
throw out what I have working to the public now in an attempt to get
feedback while I move on to figuring out how to plug into the django
settings page.
sessions.py --- The classes
''' session.py - session class using google appengine datastore
by: Joe Bowman'''
# main python imports
import sha, Cookie, os
# google appengine import
from google.appengine.ext import db
class Sessions(db.Model):
sid = db.StringProperty()
ip = db.StringProperty()
ua = db.StringProperty()
lastActivity = db.DateTimeProperty(auto_now=True)
data = db.BlobProperty()
class SessionsData(db.Model):
sid = db.ReferenceProperty(Sessions)
keyname = db.StringProperty()
content = db.StringProperty()
class Session(object):
''' Session data is kept in the datastore, with a cookie installed
on the browser with a
session id used to reference. The session also stores the user
agent and ip of the
browser to help limit session spoofing. Session data is stored
in a referenced entity
for each item in the datastore.'''
def __init__(self):
''' When instantiated, always check the cookie and create a
new one if necessary.'''
string_cookie = os.environ.get('HTTP_COOKIE', '')
self.cookie = Cookie.SimpleCookie()
self.cookie.load(string_cookie)
if self.cookie.get('sid'):
sid = self.cookie['sid'].value
if self.validateSid(sid) != True:
sid = self.newSid()
self.cookie['sid'] = sid
print self.cookie
else:
sid = self.newSid()
self.cookie['sid'] = sid
print self.cookie
''' This put is to update the lastActivity field in the
datastore. So that every time
the sessions is accessed, the lastActivity gets
updated.'''
self.sess.put()
def newSid(self):
''' newSid will create a new session id, and store it in a
cookie in the browser and then
instantiate the session in the database.'''
sid = sha.new(repr(time.time())).hexdigest()
self.cookie['sid'] = sid
self.sess = Sessions()
self.sess.ua = os.environ['HTTP_USER_AGENT']
self.sess.ip = os.environ['REMOTE_ADDR']
self.sess.sid = sid
self.sess.put()
return sid
def validateSid(self, sid = None):
''' validateSid is used to determine if a session cookie
passed from the browser is valid. It
confirms the session id exists in the data store, and the
compares the user agent and ip
information stored against the browser to validate it.'''
if sid == None:
return None
self.sess = self.__getSession(sid)
if self.sess == None or
self.sess.ua !=
os.environ['HTTP_USER_AGENT'] or self.sess.ip !=
os.environ['REMOTE_ADDR']:
return None
else:
return True
def __getSession(self, sid = None):
''' __getSession uses a session id to return a session from
the datastore.'''
if sid == None:
return None
sessions = Sessions.gql("WHERE sid = :1 AND ua = :2 LIMIT 1",
sid, os.environ['HTTP_USER_AGENT'])
if sessions.count() == 0:
return None
else:
return sessions[0]
def validateSid(self, sid = None):
''' validateSid is used to determine if a session cookie
passed from the browser is valid. It
confirms the session id exists in the data store, and the
compares the user agent and ip
information stored against the browser to validate it.'''
if sid == None:
return None
self.sess = self.__getSession(sid)
if self.sess == None or
self.sess.ua !=
os.environ['HTTP_USER_AGENT'] or self.sess.ip !=
os.environ['REMOTE_ADDR']:
return None
else:
return True
def __getSession(self, sid = None):
''' __getSession uses a session id to return a session from
the datastore.'''
if sid == None:
return None
sessions = Sessions.gql("WHERE sid = :1 AND ua = :2 LIMIT 1",
sid, os.environ['HTTP_USER_AGENT'])
if sessions.count() == 0:
return None
else:
return sessions[0]
views.py -- the time demo updated to include some sessions testing as
well
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
from utilities import session
import datetime
def current_datetime(request):
sess = session.Session()
now = datetime.datetime.now()
sess.putData("testkey", "I am testkey")
sess.putData("testkey2", "I am testkey2")
testkey = sess.getData("testkey").content
testkey2 = sess.getData("testkey2")
datalist = sess.getData()
t = get_template('time.html')
html = t.render(Context({'current_date': now, "testkey": testkey,
"testkey2": testkey2, "datalist": datalist}))
return HttpResponse(html)
time.html --- the time template
{% block content %}
<p>It is now {{ current_date }}.</p>
Testkey just content: {{ testkey }}<br />
Testkey2 attributes:
<ul>
<li>keyname: testkey2.keyname</li>
<li>content: testkey2.content</li>
</ul>
Testkeys: <ul>
{% for data in datalist %}
<li>{{data.keyname }} = {{data.content }}</li>
{% endfor %}
</ul>
{% endblock %}