tornado的session的简单实现,使用的是redis,其实一般情况,使用secure cookie不用session也行
session.py
# -*- coding: utf-8 -*- from hashlib import sha1 import os, time session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest() class SessionHandler(object): _id = None _prefix = "_session:" _skip = ["_redis", "_request", "_id", "lastActive", "_prefix", "session_lifetime"] def __init__(self, request, redis, session_lifetime=60 * 60 * 24): self._request = request self._redis = redis self.session_lifetime = session_lifetime self.init_session() def init_session(self): """初始化""" _id = self._request.get_secure_cookie("session_id") if not _id: _id = session_id() else: if not self._redis.exists(_id): _id = session_id() self._request.set_secure_cookie("session_id", _id) self._id = _id def __getattr__(self, name): if name in self._skip: return object.__getattr__(self, name) else: return self._redis.hget(self._id, name) def __setattr__(self, name, value): if name in self._skip: object.__setattr__(self, name, value) else: self.init_session() self._redis.hset(self._id, name, value) self._redis.expire(self._id, self.session_lifetime) def __delattr__(self, name): if name in self._skip: object.__delattr__(self, name) else: return self._redis.hdel(self._id, name) __all__ = ["SessionHandler", "session_id"]
test_session.py
# -*- coding: utf-8 -*- from tornado.web import RequestHandler, Application from tornado.ioloop import IOLoop from session import SessionHandler from redis import client from tornado import escape import tornado.web class BaseHandler(RequestHandler): def initialize(self): redis = self.application.redis self.session = self.application.SessionHandler(self, redis, session_lifetime=20) self.current_password = self.session.password def get_current_user(self): return self.get_secure_cookie("username") class MainHandler(BaseHandler): def get(self): if not self.current_user or not self.current_password: self.redirect("/login") return name = escape.xhtml_escape(self.current_user) self.write("Home Page | Logined | %s" % name) class LoginHandler(BaseHandler): def get(self): if self.current_user and not self.current_password: html = """\ <html> <body> <p> session超时了,要重新输入密码! </p> <form action="/login" method="post"> Password:<input type="password" name="password"> <input type="submit" value="sign in"> </form> </body> </html> """ else: html = """\ <html> <body> <p> 未登录,或者cookie超时了,要重新输入用户名和密码! </p> <form action="/login" method="post"> Username:<input type="text" name="username"> Password:<input type="password" name="password"> <input type="submit" value="sign in"> </form> </body> </html> """ self.write(html) def post(self): username = self.get_secure_cookie("username") or self.get_argument("username") password = self.get_argument("password") if not self.current_password: if username == "flyking" and password == "112358": self.set_secure_cookie("username", username) self.session.password = password self.redirect("/") else: raise tornado.web.HTTPError(403, "user or password error") else: self.redirect("/") urls = [ (r"/", MainHandler), (r"/login", LoginHandler), ] settings = { "cookie_secret":"61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=", # 带签名的cookie "login_url":"/login", # "xsrf_cookies":"Ture", # 跨站伪造请求(Cross-site request forgery) 防范策略 xsrf_cookies } app = Application(urls, **settings) app.listen(8888) app.redis = client.Redis() app.SessionHandler = SessionHandler IOLoop.instance().start()