tornado自定义session
简单的说:
- cookie是保存在客户端的键值对
- session是保存在服务端的键值对
- session依赖与cookie
在Django中,可以直接操作cookie和session,在flask可以直接使用一个session对象和号称安全的cookie来实现session存储,而在tornado中只支持cookie,如果要实现session怎么办,我们只能自己美化轮子
实现思路
我们知道,在tornado中,多有的请求都是由RequestHandler对象来处理的。在RequestHandler源代码中,预留了一个钩子方法initialize,该方法会在实例化RequestHandler对象时执行。因此我们继承RequestHandler,并覆写initialize方法,这样我们就可以完成一定的自定义操作。
此篇文章使用内存来实现session存储,存储在一个字典对象中,这里的字典对象,使用了jdb2模块中的对dict对象二次封装的功能,具体使用请参考:https://www.cnblogs.com/zhichaoma/p/9382937.html
对于使用redis和其他非关系型数据库存储实现思路大致相同,只是session的存储位置不同
实现代码
目录结构,手动创建一个空的nosql.db文件
session-demo/ ├── base.py ├── main.py ├── nosql.db └── test.py
main.py
# -*- coding: utf-8 -*- #程序的入口 import tornado.ioloop from tornado.httpserver import HTTPServer import tornado.web import test app = tornado.web.Application([ (r'/t1/?', test.Test1), (r'/t2/?', test.Test2), (r'/t3/?', test.Test3), (r'/t4/?', test.Test4), ], #加密cookie的密串 生成方式: #import base64, uuid #base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes cookie_secret="bQd3T8WSORUGqEdnC6gUtuCp0jUYAm0OIrWJbjHe/zPA=" ) if __name__ == '__main__': httpserver = HTTPServer(app) httpserver.bind(port=8080) httpserver.start() tornado.ioloop.IOLoop.current().start()
base.py
# -*- coding: utf-8 -*- import tornado.web import time import jdb2 # 初始化NoSQL DB noSql = jdb2.NoSql(dump=True, nosqlFile='nosql.db', dumpTime=3) session = noSql.createDB('session') class Session(): #实现session的类 def __init__(self, handler): self.handler = handler #连接对象 #两个cookie来匹配session self.random_index_str = self.handler.get_secure_cookie('_token_sson_', None) self.random_time_str = self.handler.get_secure_cookie('_tson_', None) self.random_str = '| m | z | c |' #加密的随机字串 #如果只存在_token_sson_的cookie值,则删除内存中之前保存的键值对 if self.random_index_str and not self.random_time_str: tmp = None #如果是bytes类型,转换为字符串 if isinstance(self.random_index_str, bytes): tmp = self.random_index_str.decode() session.dropKey(tmp) self.random_index_str = None #如果只存在_tson_的cookie值,则删除内存中之前保存的键值对 elif self.random_time_str and not self.random_index_str: tmp = None if isinstance(self.random_time_str, bytes): tmp = self.random_time_str.decode() session.dropKey(tmp) self.random_time_str = None def __get_random_str(self): """ 获取随机加密随机字符串 """ import hashlib, time md = hashlib.md5() md.update(bytes(str(time.time()) + self.random_str, encoding='utf-8')) return md.hexdigest() def __setitem__(self, key, value): """ 设置值 """ #如果两个cookie都不存在,生成加密随机字串 if not self.random_index_str and not self.random_time_str: self.random_index_str = self.__get_random_str() self.random_time_str = self.random_index_str else: #如果两个cookie都不存在session存储的数据库中则生成随机加密字符串 if isinstance(self.random_index_str, bytes): self.random_index_str = self.random_index_str.decode() if isinstance(self.random_time_str, bytes): self.random_time_str = self.random_time_str.decode() if self.random_index_str not in session.getKeys() and \ self.random_time_str not in session.getKeys(): self.random_index_str = self.__get_random_str() self.random_time_str = self.random_index_str #将bytes转换为str类型 if isinstance(self.random_index_str, bytes): self.random_index_str = self.random_index_str.decode() #在session库中创建指定加密串的对象,之后设置键值对 session.createTable(self.random_index_str).setValue(key, value) #设置_token_sson_ cookie 当关闭浏览器时cookie self.handler.set_secure_cookie("_token_sson_", self.random_index_str,expires_days=None) #设置_tson_ cookie 设置3小时后过期 self.handler.set_secure_cookie('_tson_', self.random_index_str, expires=time.time() + 3*60**2) #设置一个cookie expires的优先级要高于expires_days def __getitem__(self, key): #将bytes转换为str类型 if isinstance(self.random_index_str, bytes): self.random_index_str = self.random_index_str.decode() if isinstance(self.random_time_str, bytes): self.random_time_str = self.random_time_str.decode() #如果两个cookie都不存的时候,直接返回None if not self.random_index_str and not self.random_time_str: return None else: #如果两个cookie相等时执行获取操作,否则之际返回None if self.random_index_str == self.random_time_str: current_user = session.getValue(self.random_index_str) if not current_user: return None else: return session.createTable(self.random_index_str).getValue(key) else: return None def __delitem__(self, key): """ delete session :param key: :return: """ random_index_str = None random_time_str = None if isinstance(self.random_index_str, bytes): random_index_str = self.random_index_str.decode() if isinstance(self.random_time_str, bytes): random_time_str = self.random_time_str.decode() #如果传入的key为空或者None,则视为要删除当前session对象, if key == None or key == '': session.dropKey(random_index_str) session.dropKey(random_time_str) self.handler.clear_cookie("_token_sson_") self.handler.clear_cookie('_tson_') else: #如果键值对不为空,则删除当前session对象的指定key if random_index_str: session.createTable(random_index_str).dropKey(key) elif random_time_str: session.createTable(random_time_str).dropKey(key) class BaseHandlers(tornado.web.RequestHandler): #继承RequestHandler,并覆写部分功能 def initialize(self): self.session = Session(self)
test.py
# -*- coding: utf-8 -*- from base import BaseHandlers class Test1(BaseHandlers): """ 获取当前session对象的指定key """ def get(self): pass def post(self, *args, **kwargs): print('1', self.session['is_login']) return self.redirect('/t3') class Test2(BaseHandlers): """ 删除session的指定key """ def get(self): del self.session['is_login'] return self.redirect('/t3') class Test3(BaseHandlers): """ 设置session """ def get(self, *args, **kwargs): self.write( """ lt;form action="/t3" method="post"gt; key: lt;input type='text' name='name' /gt; lt;input type='submit' value='submit' /gt; lt;/formgt; lt;form action="/t2" method="get"gt; lt;input type='submit' value='claer' /gt; lt;/formgt; lt;form action="/t1" method="post"gt; lt;input type='submit' value='get' /gt; lt;/formgt; lt;/formgt; lt;form action="/t4" method="post"gt; lt;input type='submit' value='clear all ' /gt; lt;/formgt; """ ) def post(self, *args, **kwargs): if self.get_argument('name') == 'test': self.session['is_login'] = True return self.redirect('/t3') class Test4(BaseHandlers): """ 删除当前session对象 """ def get(self): pass def post(self, *args, **kwargs): del self.session[''] return self.redirect('/t3')
调试过程中可以查看nosql.db文件,查看内存中session存储的变化
关于tornado cookie时间设置问题可以参考