1. 程式人生 > >【原始碼剖析】tornado-memcached-sessions —— Tornado session 支援的實現(三)

【原始碼剖析】tornado-memcached-sessions —— Tornado session 支援的實現(三)

新地址:https://github.com/AngryHacker/articles/issues/5#issue-372211594

     童鞋,我就知道你是個好學滴好孩子~來吧,讓我們進行最後的探(zuo)索(si)!

     上一次我們講到哪裡?哦。。。準備講 SessionManager 是吧,來~一個一個函式看~

 

      首先是初始化,設定金鑰, memcache 地址,session 超時時間。

 

    # 初始化需要一個用於 session 加密的 secret, memcache 地址, session 的過期時間
    def __init__(self, secret, memcached_address, session_timeout):
        self.secret = secret
        self.memcached_address = memcached_address
        self.session_timeout = session_timeout

     接著是 _fetch 方法,以 session_id  為鍵從 memcached 中取出資料,並用 pickle 反序列化解析資料:

 

 

    # 該方法用 session_id 從 memcache 中取出資料
    def _fetch(self, session_id):
        try:
            # 連線 memcache 伺服器
            mc = memcache.Client(self.memcached_address, debug=0)
            # 獲取資料
            session_data = raw_data = mc.get(session_id)
            if raw_data != None:
                # 為了重新重新整理 timeout
                mc.replace(session_id, raw_data, self.session_timeout, 0)
                # 反序列化
                session_data = pickle.loads(raw_data)
            # 如果拿到的資料是字典形式,才進行返回
            if type(session_data) == type({}):
                return session_data
            else:
                return {}
        except IOError:
            return {}

      get 經過安全檢查後,以 SessionData 的形式返回 memcached 的資料(呼叫了 _fetch)方法。

 

 

    def get(self, request_handler = None):

        # 獲取對應的 session_id 和 hmac_key
        if (request_handler == None):
            session_id = None
            hmac_key = None
        else:
            # session 的基礎還是靠 cookie
            session_id = request_handler.get_secure_cookie("session_id")
            hmac_key = request_handler.get_secure_cookie("verification")

        # session_id 不存在的時候則生成一個新的 session_id 和 hmac_key
        if session_id == None:
            session_exists = False
            session_id = self._generate_id()
            hmac_key = self._generate_hmac(session_id)
        else:
            session_exists = True

        # 檢查 hmac_key
        check_hmac = self._generate_hmac(session_id)
        # 不通過則丟擲異常
        if hmac_key != check_hmac:
            raise InvalidSessionException()

        # 新建 SessionData 物件
        session = SessionData(session_id, hmac_key)

        if session_exists:
            # 通過 _fetch 方法獲取 memcache 中該 session 的所有資料
            session_data = self._fetch(session_id)
            for key, data in session_data.iteritems():
                session[key] = data

        return session

     至於 set 方法,是為了更新 memcached 的資料。

 

 

    # 設定新的 session,需要設定 handler 的 cookie 和 memcache 客戶端
    def set(self, request_handler, session):
        # 設定瀏覽器的 cookie
        request_handler.set_secure_cookie("session_id", session.session_id)
        request_handler.set_secure_cookie("verification", session.hmac_key)
        # 用 pickle 進行序列化
        session_data = pickle.dumps(dict(session.items()), pickle.HIGHEST_PROTOCOL)
        # 連線 memcache 伺服器
        mc = memcache.Client(self.memcached_address, debug=0)
        # 寫入 memcache
        mc.set(session.session_id, session_data, self.session_timeout, 0)

      最後的兩個函式,一個是生成 session_id,另一個用 session_id 與金鑰加密後生成一個加密字串,用於驗證。

 

 

    # 生成 session_id
    def _generate_id(self):
        new_id = hashlib.sha256(self.secret + str(uuid.uuid4()))
        return new_id.hexdigest()

    # 生成 hmac_key
    def _generate_hmac(self, session_id):
        return hmac.new(session_id, self.secret, hashlib.sha256).hexdigest()

      我們在哪裡初始化了 SessionManager 呢?還記得第一篇裡面的 Application 類嗎?噢...快回去翻翻。

 

      好了,童鞋們我們放學了,大家回家吧~對本篇部落格有任何意見,拒絕吐槽!