Tornado框架05-session

咱們將許多信息放在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()複製代碼

運行結果-1

運行結果-2

  • 至此咱們就完成了基於加密cookie方式的session服務端驗證
  • 注意, 獲取加密方式的cookie的值是bytes類型的, 必定要記得轉成str類型, 不然用bytes去找str類型是沒法匹配成功, 直接會形成即便登陸成功, 也沒法訪問到admin成功的頁面(筆者就曾掉進此坑了掙扎很久)
相關文章
相關標籤/搜索