咱们将许多信息放在cookie
中势必会形成浏览器端的臃肿, 此时便须要在服务端保存本来在浏览器端的那些键值对. 在浏览器端只需存储一个表示身份的随机加密字符串, 当浏览器端访问服务端时候携带该字符串, 通过比较, 验证合法以后即可以取该用户在服务端存储的相应信息. 可是在Tornado
中并无session
的模块, 咱们须要自定义来实现.python
all.py
文件以下: web
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# 存储全部的用户信息
ALL_USER_DIC = {}复制代码
base.py
文件以下: 浏览器
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
from commons.session import Session
class BaseHandler(tornado.web.RequestHandler):
# 钩子函数, 子类初始化时候会将子类对象传入该方法中执行
def initialize(self):
# 这里将子类对象传入session中, 则之后生成的session对象中就包含处理器的实例对象
self.session = Session(self)复制代码
session.py
文件以下: 服务器
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from commons.all import ALL_USER_DIC
class Session:
def __init__(self, handler):
self.handler = handler
self.random_index_str = None
def __get_random_str(self):
import hashlib, time
# 生成md5对象
md = hashlib.md5()
# 加入自定义参数来更新md5对象
md.update(bytes(str(time.time()) + ' | own-secret', encoding='utf-8'))
# 获得加盐后的十六进制随机字符串来做为用户的索引
return md.hexdigest()
def __setitem__(self, key, value):
# 当前session对象中没有对应的索引的时候
if not self.random_index_str:
# 根据处理器对象得到浏览器传来的cookie的值
random_index_str = self.handler.get_secure_cookie("__sson__", None)
# 浏览器传来的cookie的值为空的时候, 表示该用户是第一次访问本网站
if not random_index_str:
# 为当前的新用户在当前的session对象中生成索引
self.random_index_str = self.__get_random_str()
# 为当前新用户设置cookie
self.handler.set_secure_cookie('__sson__', self.random_index_str)
# 为当前用户生成保存其相关内容的字典对象
ALL_USER_DIC[self.random_index_str] = {}
# 当浏览器传来的cookie不为空的时候
else:
# 浏览器传来的cookie非法的时候
if self.random_index_str not in ALL_USER_DIC.keys():
# 为当前非法用户生产索引
self.random_index_str = self.__get_random_str()
# 仅仅为当前非法用户生成其保存相关内容的字典对象, 避免合法老用户的字典对象被清空
ALL_USER_DIC[self.random_index_str] = {}
# 无论当前session对象有没有对应的索引都应该为他设置起相关的信息保存(固然了, 到这一步的时候通过if条件语句的过滤, 剩下来的就是刚刚建立字典对象的新用户或者非法用户, 以及其余合法的老用户了)
ALL_USER_DIC[self.random_index_str][key] = value
# 将为以上的新用户或者非法用户设置cookie的操做放在这里本无可厚非. 可是将老用户的cookie也从新设置一遍, 实际上是为老用户更新过时时间而作的
self.handler.set_secure_cookie('__sson__', self.random_index_str)
def __getitem__(self, key):
# 获取当前用户cookie中保存的索引值, 注意加密方式返回的cookie的值是bytes类型的
self.random_index_str = self.handler.get_secure_cookie('__sson__', None)
# 若索引值为空表示当前用户是新用户, 则直接返回空, 程序到此终止
if not self.random_index_str:
return None
# 索引不为空的时候
else:
self.random_index_str = str(self.random_index_str, encoding="utf-8")
# 在服务器端为保存该索引值表示当前用户是非法用户,则直接返回空
current_user = ALL_USER_DIC.get(self.random_index_str, None)
if not current_user:
return None
else:
# 直接返回合法用户指定的key的值, 没有则默认返回空
return current_user.get(key, None)复制代码
home.py
文件以下: cookie
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
from commons.base import BaseHandler
class IndexHandler(BaseHandler):
def get(self):
if self.get_argument('name', None) == 'test':
self.session['is_login'] = True
self.session['name'] = self.get_argument('name')
else:
self.write('登陆失败, 请从新登陆!')
class AdminHandler(BaseHandler):
def get(self):
if self.session['is_login']:
self.write('欢迎%s回来. ' % (self.session['name'],))
else:
self.redirect('/index')复制代码
start.py
文件以下: session
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web, tornado.ioloop
from controllers import home
if __name__ == '__main__':
settings = {
# 模板路径配置
'template_path': 'views',
"cookie_secret": 'test-secret,'
}
application = tornado.web.Application([
(r"/index", home.IndexHandler),
(r"/admin", home.AdminHandler),
], **settings)
application.listen(80)
tornado.ioloop.IOLoop.instance().start()复制代码
cookie
方式的session
服务端验证cookie
的值是bytes
类型的, 必定要记得转成str
类型, 不然用bytes
去找str
类型是没法匹配成功, 直接会形成即便登陆成功, 也没法访问到admin
成功的页面(笔者就曾掉进此坑了挣扎很久)