咱們將許多信息放在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
成功的頁面(筆者就曾掉進此坑了掙扎很久)