tornado-session-manage-code

#-tornado #-session 编辑

交错</img>

tornado session 管理 我们在用到的tornado的session方法, 是一个开源的session代码

首先, tornado.web.RequestHandler有2个方法:

set_secure_cookie和get_secure_cookie,  就是set_cookie的加强版,  set_secure_cookie会通过create_signed_value方法为给定的cookie值和key做加密算法, 加密会结合tornado settings给定的cookie_secret设置来的, 因此tornado.web.Application在初始化的时候, cookie_secret是一定需要的哦.

而session.py要做的就是如何将通过get_secure_cookie取到的安全session value, 通过封装更方便的提供给RequestHandler来使用, 这里这个开源的session.py封装成字典的方式了, session使用时就像使用字典一样方便:

In your RequestHandler (probably in __init__),
    self.session = session.TornadoSession(self.application.session_manager, self)


After that, you can use it like this (in get(), post(), etc):
    self.session['blah'] = 1234
    self.save()
    blah = self.session['blah']

接下来是看这个session.py的代码, 具体实现方法: 代码不多, 包括TornadoSessionManager, TornadoSession两个类, 代码来自于github. 首先在初始化你的Application的时候, 需要指定一下:

application.session_manager = session.TornadoSessionManager(settings["session_secret"], settings["session_dir"]) 也就是常见的这样的代码(这个代码实在是太常见了, 只要是个tornado的应用都应该知道这个):

class Application(tornado.web.Application):
    def __init__(self):
        settings = dict(cookie_secret="y+iqu2psQRyVqvC0UQDB+iDnfI5g3E5Yivpm62TDmUU=",
              session_secret='ttesttt',
              session_dir='sessions',
         )
        tornado.web.Application.__init__(self, handlers, **settings)
        application.session_manager = session.TornadoSessionManager(settings["session_secret"], settings["session_dir"])



def main(port):
    tornado.options.parse_command_line()
    print "start on port %s..." % port
    http_server = tornado.httpserver.HTTPServer(Application(), xheaders=True)
    http_server.listen(port, address='0.0.0.0')
    tornado.autoreload.start()
    tornado.ioloop.IOLoop.instance().start() 来看session.py里TornadoSessionManager具体的逻辑:   TornadoSessionManager继承于SessionManager, 它提供2个方法: get和set,  作用是根据RequestHandler对象, 获取和更新secure_cookie:

def get(self, requestHandler=None):
    if requestHandler == None:
        return super(TornadoSessionManager, self).get()
    else:
        session_id = requestHandler.get_secure_cookie("session_id")
        hmac_digest = requestHandler.get_secure_cookie("hmac_digest")
        return super(TornadoSessionManager, self).get(session_id, hmac_digest)


def set(self, requestHandler, session):
    requestHandler.set_secure_cookie("session_id", session.session_id)
    requestHandler.set_secure_cookie("hmac_digest", session.hmac_digest)
    return super(TornadoSessionManager, self).set(session) 它的父类SessionManager的几个方法, 目的是为了当这个requesthandler是第一次产生session时, 产生一个新的对应这个session_id的hmac_digest,  并存储,   然后返回这个存储, 这个存储的具体逻辑可以自己定义, 比如可以使用序列化后的文件存储在本地的session_dir目录, 也可以使用memcache,   直接将这个新的session_id和它的hmac_digest存储在一个字典内,然后set进memcache,  我们使用的是后者.  

另外SessionManager还会做一个hmac_digest的校验, 当requestHandler不是None的时候, 当然是通过tornado的get_secure_cookie去取session_id:

session_id = requestHandler.get_secure_cookie("session_id")
hmac_digest = requestHandler.get_secure_cookie("hmac_digest") 然后通过取到的session_id和hmac_digest,  通过session_id从存储内取出服务器上次算出的正确的hmac_digest和这里的hmac_digest做比对, 来达到session验证效果.

上面初始化TornadoSessionManager完成, 然后是在RequestHandler里使用它了:

class  MainHandler(tornado.web.RequestHandler):
     def __init__(self, *argc, **argkw):
          super(BaseHandler, self).__init__(*argc, **argkw)
          self.session = session.TornadoSession(self.application.session_manager, self) 这里重写了tornado.web.RequestHandler的__init__方法.

后面的逻辑是, 初始化一个session.TornadoSession实例, 2个参数分别一个是之前初始化后的session.TornadoSessionManager对象, 和RequestHandler自己本身(self对象) 我们来看TornadoSession类, 它继承了一个叫Session的父类, 这个父类非常简单, 只是个继承于字典类型的类:

class Session(dict):
    def __init__(self, session_id, hmac_digest):
        self.session_id = session_id
        self.hmac_digest = hmac_digest 来看TornadoSession类里的逻辑, 它通过tornado_session_manager和request_handler初始化, 而后的逻辑是:

class TornadoSession(Session):
    def __init__(self, tornado_session_manager, request_handler):
        self.session_manager = tornado_session_manager
        self.request_handler = request_handler
        try:
            plain_session = tornado_session_manager.get(request_handler)
        except InvalidSessionException:
            plain_session = tornado_session_manager.get()


        for i, j in plain_session.iteritems():
            self[i] = j
        self.session_id = plain_session.session_id
        self.hmac_digest = plain_session.hmac_digest


    def save(self):
        self.session_manager.set(self.request_handler, self)

首先tornado_session_manager也就是之前初始化的TornadoSessionManager, get本request_handler的session存储,
如果此request_handler里能通过get_secure_cookie取到’session_id’, 则会做验证, 验证通过后, 返回这个request_handler的session数据,
在之前我们用的是存储在memcache里的字典结构; 如果是一个新的session_id则会经过TornadoSessionManager之前的逻辑产生新的hmac_digest, 同时会被(当然需要你执行save session操作时):

requestHandler.set_secure_cookie("session_id", session.session_id)
requestHandler.set_secure_cookie("hmac_digest", session.hmac_digest) 以提供给下一次应用请求数据时做session校验. save方法, 用来更新浏览器的session_id和对应的hmac_digest,  当然,同时也会更新服务器本地存储里的数据.

到此tornado的session就完成了.