tornado--之cookie自定义(还有session)

时间:2020-12-15 20:38:05

tornado--之cookie自定义(还有session)

什么是Cookies(“小甜饼”)呢?

简单来说,Cookies就是服务器暂时存放在你的电脑里的资料(.txt格式的文本文件),好让服务器用来辨认 你的计算机。

当你在浏览网站的时候,Web服务器会先送一小小资料放在你的计算机上,Cookies 会把你在网站上所打的文字或是一些选择都记录下来。

当下次你再访问同一个网站,Web服务器会先看看有没有它上次留下的Cookies资料,有的话,就会 依据Cookie里的内容来判断使用者,送出特定的网页内容给你。

Tornado中可以对cookie进行操作,并且还可以对cookie进行签名以放置伪造。

1、基本操作

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        if not self.get_cookie("mycookie"):
            self.set_cookie("mycookie", "myvalue")
            self.write("Your cookie was not set yet!")
        else:
            self.write("Your cookie was set!")

2、加密cookie(签名)

Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        if not self.get_secure_cookie("mycookie"):
            self.set_secure_cookie("mycookie", "myvalue")
            self.write("Your cookie was not set yet!")
        else:
            self.write("Your cookie was set!")
             
application = tornado.web.Application([
    (r"/", MainHandler),
], cookie_secret="61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=")
View Code
tornado--之cookie自定义(还有session)
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
def _create_signature_v1(secret, *parts):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
    for part in parts:
        hash.update(utf8(part))
    return utf8(hash.hexdigest())

# 加密
def _create_signature_v2(secret, s):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)
    hash.update(utf8(s))
    return utf8(hash.hexdigest())

def create_signed_value(secret, name, value, version=None, clock=None,
                        key_version=None):
    if version is None:
        version = DEFAULT_SIGNED_VALUE_VERSION
    if clock is None:
        clock = time.time

    timestamp = utf8(str(int(clock())))
    value = base64.b64encode(utf8(value))
    if version == 1:
        signature = _create_signature_v1(secret, name, value, timestamp)
        value = b"|".join([value, timestamp, signature])
        return value
    elif version == 2:
        # The v2 format consists of a version number and a series of
        # length-prefixed fields "%d:%s", the last of which is a
        # signature, all separated by pipes.  All numbers are in
        # decimal format with no leading zeros.  The signature is an
        # HMAC-SHA256 of the whole string up to that point, including
        # the final pipe.
        #
        # The fields are:
        # - format version (i.e. 2; no length prefix)
        # - key version (integer, default is 0)
        # - timestamp (integer seconds since epoch)
        # - name (not encoded; assumed to be ~alphanumeric)
        # - value (base64-encoded)
        # - signature (hex-encoded; no length prefix)
        def format_field(s):
            return utf8("%d:" % len(s)) + utf8(s)
        to_sign = b"|".join([
            b"2",
            format_field(str(key_version or 0)),
            format_field(timestamp),
            format_field(name),
            format_field(value),
            b''])

        if isinstance(secret, dict):
            assert key_version is not None, 'Key version must be set when sign key dict is used'
            assert version >= 2, 'Version must be at least 2 for key version support'
            secret = secret[key_version]

        signature = _create_signature_v2(secret, to_sign)
        return to_sign + signature
    else:
        raise ValueError("Unsupported version %d" % version)

# 解密
def _decode_signed_value_v1(secret, name, value, max_age_days, clock):
    parts = utf8(value).split(b"|")
    if len(parts) != 3:
        return None
    signature = _create_signature_v1(secret, name, parts[0], parts[1])
    if not _time_independent_equals(parts[2], signature):
        gen_log.warning("Invalid cookie signature %r", value)
        return None
    timestamp = int(parts[1])
    if timestamp < clock() - max_age_days * 86400:
        gen_log.warning("Expired cookie %r", value)
        return None
    if timestamp > clock() + 31 * 86400:
        # _cookie_signature does not hash a delimiter between the
        # parts of the cookie, so an attacker could transfer trailing
        # digits from the payload to the timestamp without altering the
        # signature.  For backwards compatibility, sanity-check timestamp
        # here instead of modifying _cookie_signature.
        gen_log.warning("Cookie timestamp in future; possible tampering %r",
                        value)
        return None
    if parts[1].startswith(b"0"):
        gen_log.warning("Tampered cookie %r", value)
        return None
    try:
        return base64.b64decode(parts[0])
    except Exception:
        return None


def _decode_fields_v2(value):
    def _consume_field(s):
        length, _, rest = s.partition(b':')
        n = int(length)
        field_value = rest[:n]
        # In python 3, indexing bytes returns small integers; we must
        # use a slice to get a byte string as in python 2.
        if rest[n:n + 1] != b'|':
            raise ValueError("malformed v2 signed value field")
        rest = rest[n + 1:]
        return field_value, rest

    rest = value[2:]  # remove version number
    key_version, rest = _consume_field(rest)
    timestamp, rest = _consume_field(rest)
    name_field, rest = _consume_field(rest)
    value_field, passed_sig = _consume_field(rest)
    return int(key_version), timestamp, name_field, value_field, passed_sig


def _decode_signed_value_v2(secret, name, value, max_age_days, clock):
    try:
        key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value)
    except ValueError:
        return None
    signed_string = value[:-len(passed_sig)]

    if isinstance(secret, dict):
        try:
            secret = secret[key_version]
        except KeyError:
            return None

    expected_sig = _create_signature_v2(secret, signed_string)
    if not _time_independent_equals(passed_sig, expected_sig):
        return None
    if name_field != utf8(name):
        return None
    timestamp = int(timestamp)
    if timestamp < clock() - max_age_days * 86400:
        # The signature has expired.
        return None
    try:
        return base64.b64decode(value_field)
    except Exception:
        return None


def get_signature_key_version(value):
    value = utf8(value)
    version = _get_version(value)
    if version < 2:
        return None
    try:
        key_version, _, _, _, _ = _decode_fields_v2(value)
    except ValueError:
        return None

    return key_version
内部算法

签名Cookie的本质是:

    写cookie过程:

        将值进行base64加密
        对除值以外的内容进行签名,哈希算法(无法逆向解析)
        拼接 签名 + 加密值

    读cookie过程:

        读取 签名 + 加密值
        对签名进行验证
        base64解密,获取值内容
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web


class MainHandler(tornado.web.RequestHandler):

    def get(self):
        login_user = self.get_secure_cookie("login_user", None)
        if login_user:
            self.write(login_user)
        else:
            self.redirect('/login')


class LoginHandler(tornado.web.RequestHandler):
    def get(self):
        # self.current_user()

        self.render('login.html',)

    def post(self, *args, **kwargs):

        username = self.get_argument('user')
        password = self.get_argument('pwd')
        if username == 'wupeiqi' and password == '123':
            self.set_secure_cookie('login_user', '拉条骚')
            self.write("成功")
            # self.redirect('/')
        else:
            self.render('login.html', **{'status': '用户名或密码错误'})

settings = {
    'template_path': 'template',
    'static_path': 'static',
    'static_url_prefix': '/static/',
    'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh'
}

application = tornado.web.Application([
    (r"/index", MainHandler),
    (r"/login", LoginHandler),
], **settings)


if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
基于cookie实现用户验证:cookie.py
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="post">
        <input type="text" name="user">
        <input type="text" name="pwd">
        <input type="submit" value="提交">
    </form>
</body>
</html>
login.html
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
</html>
index.html

注意提交表单的时候要写路径

3、JavaScript操作Cookie

由于Cookie保存在浏览器端,所以在浏览器端也可以使用JavaScript来操作Cookie。

/*
设置cookie,指定秒数过期
 */
function setCookie(name,value,expires){
    var temp = [];
    var current_date = new Date();
    current_date.setSeconds(current_date.getSeconds() + 5);
    document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
}

 

对于参数:

  • domain   指定域名下的cookie
  • path       域名下指定url中的cookie
  • secure    https使用

注:jQuery中也有指定的插件 jQuery Cookie 专门用于操作cookie,猛击这里

 

-----------------------------------------session

session

1、面向对象基础

面向对象中通过索引的方式访问对象,需要内部实现 __getitem__ 、__delitem__、__setitem__方法

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
   
class Foo(object):
   
    def __getitem__(self, key):
        print  '__getitem__',key
   
    def __setitem__(self, key, value):
        print '__setitem__',key,value
   
    def __delitem__(self, key):
        print '__delitem__',key
   
   
   
obj = Foo()
result = obj['k1']
#obj['k2'] = 'wupeiqi'
#del obj['k1']
View Code

2、Tornado扩展

Tornado框架中,默认执行Handler的get/post等方法之前默认会执行 initialize方法,所以可以通过自定义的方式使得所有请求在处理前执行操作...

class BaseHandler(tornado.web.RequestHandler):
   
    def initialize(self):
        self.xxoo = "wupeiqi"
   
   
class MainHandler(BaseHandler):
   
    def get(self):
        print(self.xxoo)
        self.write('index')
 
class IndexHandler(BaseHandler):
   
    def get(self):
        print(self.xxoo)
        self.write('index')

 

 

 

tornado--之cookie自定义(还有session)

tornado--之cookie自定义(还有session)

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
#!/usr/bin/env python
import tornado.web
import tornado.ioloop

container = {}
# container = {
#     # "第一个人的随机字符串":{},
#     # "第一个人的随机字符串":{'k1': 111, 'parents': ''},
# }

class Session:
    def __init__(self, handler):
        self.handler = handler   #定义self.handler是为了可以通过对象调用set_cookie
        self.random_str = None

    def __genarate_random_str(self):  #获取加密的随机数字
        import hashlib
        import time
        obj = hashlib.md5()
        obj.update(bytes(str(time.time()), encoding='utf-8'))
        random_str = obj.hexdigest()
        return random_str

    def __setitem__(self, key,value):
        # 在container中加入随机字符串
        # 定义专属于自己的数据
        # 在客户端中写入随机字符串
        # 判断,请求的用户是否已有随机字符串
        if not self.random_str:  #如果没有的话
            random_str = self.handler.get_cookie('__kakaka__')
            if not random_str:
                random_str = self.__genarate_random_str()
                container[random_str] = {}
            else:
                # 客户端有随机字符串
                if random_str in container.keys():
                    pass
                else:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
            self.random_str = random_str # self.random_str = asdfasdfasdfasdf

        container[self.random_str][key] = value
        self.handler.set_cookie("__kakaka__", self.random_str)

    def __getitem__(self,key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__kakaka__")#拿到的是随机字符串
        if not random_str:
            return None
        # 客户端有随机字符串
        user_info_dict = container.get(random_str,None)#拿到的是字典信息
        if not user_info_dict:#如果没有字典返回none
            return None
        value = user_info_dict.get(key, None)#通过key,返回value
        return value
注释版自定义session理解
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = Session(self)

class IndexHandler(BaseHandler):
    def get(self):
        if self.get_argument('u', None) in ['alex','eric']:
            # s = Session(self)
            self.session['is_login'] = True
            self.session['name'] = self.get_argument('u',None)
            # self.session.get_value('islogin', True)
            # self.session.set_value('name', self.get_argument('u', None))
            print(container)
        else:
            self.write("奇怪登陆")

class ManagerHandler(BaseHandler):
    def get(self):
        # s = Session(self)
        # val = self.session.get_value('is_login')
        val = self.session['is_login']
        if val:
            self.write(self.session['name'])
        else:
            self.write("失败")
模拟调用session,app.py

 --------

为了方便理解写了个小例子

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import  tornado.ioloop
import tornado.web
import io
import check_code


#!/usr/bin/env python
import tornado.web
import tornado.ioloop

container = {}
# container = {
#     # "第一个人的随机字符串":{},
#     # "第一个人的随机字符串":{'k1': 111, 'parents': ''},
# }

class Session:
    def __init__(self, handler):
        self.handler = handler   #定义self.handler是为了可以通过对象调用set_cookie
        self.random_str = None

    def __genarate_random_str(self):
        import hashlib
        import time
        obj = hashlib.md5()
        obj.update(bytes(str(time.time()), encoding='utf-8'))
        random_str = obj.hexdigest()
        return random_str

    def __setitem__(self, key,value):
        # 在container中加入随机字符串
        # 定义专属于自己的数据
        # 在客户端中写入随机字符串
        # 判断,请求的用户是否已有随机字符串
        if not self.random_str:  #如果没有的话
            random_str = self.handler.get_cookie('__kakaka__')
            if not random_str:
                random_str = self.__genarate_random_str()
                container[random_str] = {}
            else:
                # 客户端有随机字符串
                if random_str in container.keys():
                    pass
                else:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
            self.random_str = random_str # self.random_str = asdfasdfasdfasdf

        container[self.random_str][key] = value
        self.handler.set_cookie("__kakaka__", self.random_str)

    def __getitem__(self,key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__kakaka__")
        if not random_str:
            return None
        # 客户端有随机字符串
        user_info_dict = container.get(random_str,None)
        if not user_info_dict:
            return None
        value = user_info_dict.get(key, None)
        return value






class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = Session(self)

class IndexHandler(BaseHandler):
    def get(self):
        if self.get_argument('u', None) in ['alex','eric']:
            # s = Session(self)
            self.session['is_login'] = True
            self.session['name'] = self.get_argument('u',None)
            # self.session.get_value('islogin', True)
            # self.session.set_value('name', self.get_argument('u', None))
            print(container)
        else:
            self.write("已经登陆")

class ManagerHandler(BaseHandler):
    def get(self):
        # s = Session(self)
        # val = self.session.get_value('is_login')
        val = self.session['is_login']
        if val:
            self.write(self.session['name'])
        else:
            self.write("失败")


settings = {
    'template_path': 'views',
    'static_path': 'statics',
    'static_url_prefix':'/statics/',
    'xsrf_cookies':True
}

application = tornado.web.Application([
    (r"/index", IndexHandler),
    (r"/manager", ManagerHandler),
    # (r"/login", LoginHandler),
    # (r"/check_code", CheckCodeHandler),
    # (r"/csrf", CsrfHandler),
], **settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
start.py
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    /*
    浏览器测试:document.cookie
    setCookie('k88', 'adf', 5)
    document.cookie查看
    设置cookie, 指定秒数过期
    * */

    function  setCookie(name, value, expires) {
        var current_date = new Date();
//        设置获取时间秒数+5为当前时间
        current_date.setSeconds(current_date.getSeconds() + 5)
        document.cookie = name + "=" + value + ";expires=" + current_date.toUTCString();
    }
</script>
</body>
</html>
index.html

 

分布式session(还没讲--后面讲)

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
#!/usr/bin/env python
#coding:utf-8

import sys
import math
from bisect import bisect


if sys.version_info >= (2, 5):
    import hashlib
    md5_constructor = hashlib.md5
else:
    import md5
    md5_constructor = md5.new


class HashRing(object):
    """一致性哈希"""
    
    def __init__(self,nodes):
        '''初始化
        nodes : 初始化的节点,其中包含节点已经节点对应的权重
                默认每一个节点有32个虚拟节点
                对于权重,通过多创建虚拟节点来实现
                如:nodes = [
                        {'host':'127.0.0.1:8000','weight':1},
                        {'host':'127.0.0.1:8001','weight':2},
                        {'host':'127.0.0.1:8002','weight':1},
                    ]
        '''
        
        self.ring = dict()
        self._sorted_keys = []

        self.total_weight = 0
        
        self.__generate_circle(nodes)
        
            
            
    def __generate_circle(self,nodes):
        for node_info in nodes:
            self.total_weight += node_info.get('weight',1)
            
        for node_info in nodes:
            weight = node_info.get('weight',1)
            node = node_info.get('host',None)
                
            virtual_node_count = math.floor((32*len(nodes)*weight) / self.total_weight)
            for i in xrange(0,int(virtual_node_count)):
                key = self.gen_key_thirty_two( '%s-%s' % (node, i) )
                if self._sorted_keys.__contains__(key):
                    raise Exception('该节点已经存在.')
                self.ring[key] = node
                self._sorted_keys.append(key)
            
    def add_node(self,node):
        ''' 新建节点
        node : 要添加的节点,格式为:{'host':'127.0.0.1:8002','weight':1},其中第一个元素表示节点,第二个元素表示该节点的权重。
        '''
        node = node.get('host',None)
        if not node:
                raise Exception('节点的地址不能为空.')
                
        weight = node.get('weight',1)
        
        self.total_weight += weight
        nodes_count = len(self._sorted_keys) + 1
        
        virtual_node_count = math.floor((32 * nodes_count * weight) / self.total_weight)
        for i in xrange(0,int(virtual_node_count)):
            key = self.gen_key_thirty_two( '%s-%s' % (node, i) )
            if self._sorted_keys.__contains__(key):
                raise Exception('该节点已经存在.')
            self.ring[key] = node
            self._sorted_keys.append(key)
        
    def remove_node(self,node):
        ''' 移除节点
        node : 要移除的节点 '127.0.0.1:8000'
        '''
        for key,value in self.ring.items():
            if value == node:
                del self.ring[key]
                self._sorted_keys.remove(key)
    
    def get_node(self,string_key):
        '''获取 string_key 所在的节点'''
        pos = self.get_node_pos(string_key)
        if pos is None:
            return None
        return self.ring[ self._sorted_keys[pos]].split(':')
    
    def get_node_pos(self,string_key):
        '''获取 string_key 所在的节点的索引'''
        if not self.ring:
            return None
            
        key = self.gen_key_thirty_two(string_key)
        nodes = self._sorted_keys
        pos = bisect(nodes, key)
        return pos
    
    def gen_key_thirty_two(self, key):
        
        m = md5_constructor()
        m.update(key)
        return long(m.hexdigest(), 16)
        
    def gen_key_sixteen(self,key):
        
        b_key = self.__hash_digest(key)
        return self.__hash_val(b_key, lambda x: x)

    def __hash_val(self, b_key, entry_fn):
        return (( b_key[entry_fn(3)] << 24)|(b_key[entry_fn(2)] << 16)|(b_key[entry_fn(1)] << 8)| b_key[entry_fn(0)] )

    def __hash_digest(self, key):
        m = md5_constructor()
        m.update(key)
        return map(ord, m.digest())


"""
nodes = [
    {'host':'127.0.0.1:8000','weight':1},
    {'host':'127.0.0.1:8001','weight':2},
    {'host':'127.0.0.1:8002','weight':1},
]

ring = HashRing(nodes)
result = ring.get_node('98708798709870987098709879087')
print result

"""
一致性哈希
tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
from hashlib import sha1
import os, time


create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()


class Session(object):

    session_id = "__sessionId__"

    def __init__(self, request):
        session_value = request.get_cookie(Session.session_id)
        if not session_value:
            self._id = create_session_id()
        else:
            self._id = session_value
        request.set_cookie(Session.session_id, self._id)

    def __getitem__(self, key):
        # 根据 self._id ,在一致性哈西中找到其对应的服务器IP
        # 找到相对应的redis服务器,如: r = redis.StrictRedis(host='localhost', port=6379, db=0)
        # 使用python redis api 链接
        # 获取数据,即:
        # return self._redis.hget(self._id, name)

    def __setitem__(self, key, value):
        # 根据 self._id ,在一致性哈西中找到其对应的服务器IP
        # 使用python redis api 链接
        # 设置session
        # self._redis.hset(self._id, name, value)


    def __delitem__(self, key):
        # 根据 self._id 找到相对应的redis服务器
        # 使用python redis api 链接
        # 删除,即:
        return self._redis.hdel(self._id, name)
先写上session

 

之前欠的东西总算补上了

session 模块

tornado--之cookie自定义(还有session)tornado--之cookie自定义(还有session)
#!/usr/bin/env python
# -*- coding:utf-8 -*-


from hashlib import sha1
import os
import time
import memcache
import json
import redis
from common.Base import Config

"""
注释:
    这个是tornado封装的session
    适用于cache , memcache, redis
    注意需要使用那个需要在config.py 里面拿数据才ok
    同时把之前的tornado.web继承 的类用tornado的钩子函数封装,并继承,然后调用即可
    这个类在core.request_handler.py

```
import tornado.web

from comm.session.session import SessionFactory

class BaseRequestHandler(tornado.web.RequestHandler):

    def initialize(self):

        self.session = SessionFactory.get_session_obj(self)
        self.session['is_login'] = True
        self.session['name']= self.get_argument('u',None)
```
# Session
[session]
# 类型: Cache/Redis/Memcached
session_type = redis
# session 超时时间
session_expires = 20
"""

create_session_id = lambda: sha1(bytes('%s%s' % (os.urandom(16), time.time()), encoding='utf-8')).hexdigest()

sessionConfig = Config().get_content("session")


class config:
    SESSION_TYPE = sessionConfig["session_type"]
    SESSION_EXPIRES = sessionConfig["session_expires"]


class SessionFactory:
    @staticmethod
    def get_session_obj(handler):
        obj = None

        if config.SESSION_TYPE == "cache":
            obj = CacheSession(handler)
        elif config.SESSION_TYPE == "memcached":
            obj = MemcachedSession(handler)
        elif config.SESSION_TYPE == "redis":
            obj = RedisSession(handler)
        return obj


"""
    基于内存的session
"""


class CacheSession:
    session_container = {}
    session_id = "__sessionId__"

    def __init__(self, handler):
        self.handler = handler
        client_random_str = handler.get_cookie(CacheSession.session_id, None)
        if client_random_str and client_random_str in CacheSession.session_container:
            self.random_str = client_random_str
        else:
            self.random_str = create_session_id()
            CacheSession.session_container[self.random_str] = {}

        expires_time = time.time() + config.SESSION_EXPIRES
        handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time)

    def __getitem__(self, key):
        ret = CacheSession.session_container[self.random_str].get(key, None)
        return ret

    def __setitem__(self, key, value):
        CacheSession.session_container[self.random_str][key] = value

    def __delitem__(self, key):
        if key in CacheSession.session_container[self.random_str]:
            del CacheSession.session_container[self.random_str][key]


# class MemcachedSession:
#     def __init__(self, handler):
# 获取memcache的连接
conn = memcache.Client(['192.168.11.201:12000'], debug=True, cache_cas=True)


class MemcachedSession:
    session_id = "__sessionId__"

    def __init__(self, handler):
        self.handler = handler
        # 从客户端获取随机字符串
        client_random_str = handler.get_cookie(MemcachedSession.session_id, None)
        # 如果从客户端获取到了随机字符串
        #
        if client_random_str and conn.get(client_random_str):
            self.random_str = client_random_str
        else:
            self.random_str = create_session_id()
            # 设置memcache的key,和value,以及超时时间
            conn.set(self.random_str, json.dumps({}), config.SESSION_EXPIRES)
            # CacheSession.session_container[self.random_str] = {}

        # 这句存在的意义就是当改变以后会重新设置超时时间
        conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES)

        expires_time = time.time() + config.SESSION_EXPIRES
        # self...设置客户端的cookie,客户端的key,value,超时时间
        handler.set_cookie(MemcachedSession.session_id, self.random_str, expires=expires_time)

    def __getitem__(self, key):
        # ret = CacheSession.session_container[self.random_str].get(key, None)
        # 获取key
        ret = conn.get(self.random_str)
        # 转换成字典
        ret_dict = json.loads(ret)
        # none是如果没有值设置默认值
        result = ret_dict.get(key, None)
        return result

    def __setitem__(self, key, value):
        # 获取key
        ret = conn.get(self.random_str)
        ret_dict = json.loads(ret)
        # 这是字典里面的内容
        ret_dict[key] = value
        # 设置超时时间
        conn.set(self.random_str, json.dumps(ret_dict), config.SESSION_EXPIRES)

        # CacheSession.session_container[self.random_str][key] = value

    def __delitem__(self, key):
        ret = conn.get(self.random_str)
        ret_dict = json.loads(ret)
        del ret_dict[key]
        conn.set(self.random_str, json.dumps(ret_dict), config.SESSION_EXPIRES)


pool = redis.ConnectionPool(host='192.168.72.128', port=6379)
r = redis.Redis(connection_pool=pool)


class RedisSession:
    session_id = "__sessionId__"

    def __init__(self, handler):
        self.handler = handler

        client_random_str = handler.get_cookie(RedisSession.session_id, None)

        if client_random_str and r.exists(client_random_str):
            self.random_str = client_random_str
        else:
            self.random_str = create_session_id()
            r.hset(self.random_str, None, None)

        r.expire(self.random_str, config.SESSION_EXPIRES)

        expires_time = time.time() + config.SESSION_EXPIRES
        handler.set_cookie(RedisSession.session_id, self.random_str, expires=expires_time)

    def __getitem__(self, key):
        result = r.hget(self.random_str, key)
        if result:
            ret_str = str(result, encoding='utf-8')
            try:
                result = json.loads(ret_str)
            except:
                result = ret_str
            return result
        else:
            return result

    def __setitem__(self, key, value):
        if type(value) == dict:
            r.hset(self.random_str, key, json.dumps(value))
        else:
            r.hset(self.random_str, key, value)

    def __delitem__(self, key):
        r.hdel(self.random_str, key)
Cache/Memcached/Redis