Last active
August 13, 2018 19:16
-
-
Save cloverstd/7395139 to your computer and use it in GitHub Desktop.
Tornado Session
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import tornado.web | |
import tornado.ioloop | |
import tornado.httpserver | |
from session import Session, RedisSessionBackend | |
import redis | |
class BaseHandler(tornado.web.RequestHandler): | |
pass | |
class IndexHandler(BaseHandler): | |
@Session | |
def get(self): | |
self.session["count"] += 1 | |
self.write("hello") | |
self.write("%r" % self.session) | |
class SessionHandler(BaseHandler): | |
@Session | |
def get(self): | |
self.session["count"] = 0 | |
self.session["permanent"] = True | |
self.session["login"] = True | |
self.write("%r" % self.session) | |
class TestHandler(BaseHandler): | |
@Session | |
def get(self): | |
self.session.pop("login") | |
self.write("Test") | |
class AllHandler(BaseHandler): | |
@Session | |
def get(self): | |
self.write("%r" % self.session) | |
class KillHandler(BaseHandler): | |
@Session | |
def get(self): | |
self.session.kill() | |
self.write("kill") | |
class Application(tornado.web.Application): | |
def __init__(self): | |
handlers = [(r'/', IndexHandler), | |
(r'/test', TestHandler), | |
(r'/s', AllHandler), | |
(r'/kill', KillHandler), | |
(r'/init', SessionHandler)] | |
settings = dict(debug=True, | |
cookie_secret="key") | |
super(Application, self).__init__(handlers=handlers, **settings) | |
self.redis = redis.StrictRedis() | |
self.session_backend = RedisSessionBackend(self.redis, secret_key="this is a key") | |
if __name__ == '__main__': | |
app = Application() | |
http_server = tornado.httpserver.HTTPServer(app) | |
http_server.listen(8888) | |
tornado.ioloop.IOLoop.instance().start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
import os, time, base64 | |
try: | |
import cPickle as pickle | |
except ImportError: | |
import pickle | |
try: | |
import hashlib | |
sha1 = hashlib.sha1 | |
except ImportError: | |
import sha | |
sha1 = sha.new | |
def _generate_session_id(backend): | |
"""Generate a random id for session""" | |
while True: | |
rand = os.urandom(16) | |
now = time.time() | |
secret_key = backend.options["secret_key"] | |
session_id = sha1("%s%s%s" %(rand, now, secret_key)) | |
session_id = session_id.hexdigest() | |
if not backend.exists(session_id): | |
break | |
return session_id | |
class SessionBackend(object): | |
""" | |
The base Session Backend class | |
""" | |
def getitem(self, key): | |
pass | |
def setitem(self, key, value, timeout): | |
pass | |
def delitem(self, key): | |
pass | |
def exists(self, key): | |
pass | |
def encode(self, session_dict): | |
"""encodes session dict as a string""" | |
pickled = pickle.dumps(session_dict) | |
return base64.encodestring(pickled) | |
def decode(self, session_data): | |
"""decodes the data to get back the session dict """ | |
pickled = base64.decodestring(session_data) | |
return pickle.loads(pickled) | |
class RedisSessionBackend(SessionBackend): | |
def __init__(self, redis_connection, **options): | |
self.options = dict(prefix="Session ID:", | |
timeout=86400, | |
#cookie_name="session_id", | |
#cookie_domain=None, | |
#cookie_path=None, | |
secret_key="", | |
) | |
self.options.update(options) | |
self.redis = redis_connection | |
def getitem(self, key): | |
if self.exists(key): | |
pickled = self.redis.get(self.prefix(key)) | |
return self.decode(pickled) | |
else: | |
#raise KeyError, key | |
return None | |
def setitem(self, key, value, timeout=None): | |
"""Default timeout: 24 * 60 * 60 seconds""" | |
pickled = self.encode(value) | |
self.redis.set(self.prefix(key), pickled) | |
if timeout: | |
self.redis.expire(self.prefix(key), timeout) | |
else: | |
self.redis.expire(self.prefix(key), self.options["timeout"]) | |
def delitem(self, key): | |
self.redis.delete(self.prefix(key)) | |
def exists(self, key): | |
return bool(self.redis.exists(self.prefix(key))) | |
def prefix(self, key): | |
return "%s%s" % (self.options["prefix"], key) | |
class SessionData(dict): | |
def __init__(self, session_id=None): | |
self.id = session_id | |
self.permanent = False | |
self.death = False | |
def __getitem__(self, key): | |
if self.has_key(key): | |
return dict.__getitem__(self, key) | |
return None | |
def kill(self): | |
self.death = True | |
def __setitem__(self, key, value): | |
dict.__setitem__(self, key, value) | |
#def __setattr__(self, key, value): | |
#self[key] = value | |
#def __getattr__(self, key): | |
#return self[key] | |
#def __delattr__(self, key): | |
#del self[key] | |
def Session(request): | |
import functools | |
@functools.wraps(request) | |
def Process(handler, *args): | |
session_id = handler.get_secure_cookie("session_id") | |
item = handler.application.session_backend.getitem(session_id) | |
data = None | |
if item: | |
data = SessionData(item.id) | |
data.update(item) | |
else: | |
data = SessionData() | |
handler.clear_cookie("session_id") | |
handler.__setattr__("session", data) | |
# excute request | |
result = request(handler, *args) | |
if data.id: | |
if data.death: | |
handler.clear_cookie("session_id") | |
handler.application.session_backend.delitem(data.id) | |
elif data["permanent"] == True: | |
handler.set_secure_cookie("session_id", data.id) | |
handler.application.session_backend.setitem(data.id, data, timeout=86400*31) | |
else: | |
handler.set_secure_cookie("session_id", data.id, expires_days=None) | |
handler.application.session_backend.setitem(data.id, data) | |
else: | |
if len(data.keys()): | |
data.id = _generate_session_id(handler.application.session_backend) | |
if data["permanent"] == True: | |
handler.set_secure_cookie("session_id", data.id) | |
handler.application.session_backend.setitem(data.id, data, timeout=86400*31) | |
else: | |
handler.set_secure_cookie("session_id", data.id, expires_days=None) | |
handler.application.session_backend.setitem(data.id, data) | |
return result | |
return Process |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment