Analyzes the implementation code supported by the session in the Tornado framework of Python.

Source: Internet
Author: User
This article mainly introduces the implementation code supported by session in the Tornado framework of Python, so that you can use sessions that are familiar to everyone in the framework such as Django, if you need a friend, can you refer to tornado without a session? No, of course ~ I know someone has helped me write it on github ~ O (distinct _ distinct) O ~
Therefore, find the following project and use memcached to implement tornado session. I can't use it. Let's see how it is written ~

Project address: tornado-memcached-sessions

Let's start with the demo ....

App. py:
First, we can note that a new Application class is defined here, which inherits from tornado. web. application, in the initialization method of this class, set the Application parameter settings, and then initialize the parent class and session_manager. (What is this? Temporarily ignore it ...)


Class Application (tornado. web. application): def _ init _ (self): settings = dict (# Set cookie_secret for secure_cookie cookie_secret = "secret = 78d ", # Set session_secret to generate session_id session_secret = "secret", # memcached address memcached_address = ["127.0.0.1: 11211"], # session expiration time session_timeout = 60, template_path = OS. path. join (OS. path. dirname (_ file _), "templates"), static_path = OS. path. join (OS. path. dirname (_ file _), "static"), xsrf_cookies = True, login_url = "/login",) handlers = [(r "/", MainHandler ), (r "/login", LoginHandler)] # initialize the parent class tornado. web. application tornado. web. application. _ init _ (self, handlers, ** settings) # initialize session_manager self for this class. session_manager = session. sessionManager (settings ["session_secret"], settings ["memcached_address"], settings ["session_timeout"])

In the following LoginHandler, we can see the usage of the session:

Class LoginHandler (BaseHandler): def get (self): self. render ("login.html") def post (self): # access self in the form of dictionary key-value pairs. session ["user_name"] = self. get_argument ("name") # modify the save of the session to be called. Otherwise, no modification is made... self. session. save () self. redirect ("/")

In terms of usage, is it very concise and clear? So, are you careful to find that the current handler does not inherit from tornado. web. RequestHandler? With the strong spirit of zuo (si), we opened base. py. Oh, my God, it's so short... (Oh, where did you go ...)
The BaseHandler method only initializes and overwrites the get_current_user Method for user login verification.

Class BaseHandler (tornado. web. requestHandler): def _ init _ (self, * argc, ** argkw): super (BaseHandler, self ). _ init _ (* argc, ** argkw) # defines the handler session. Note that a Session instance will be initialized for each access according to HTTP characteristics, this is very important for your subsequent understanding of self. session = session. session (self. application. session_manager, self) # What is this? Used to verify login... please google about tornado. web. authenticated, in fact, is the user verification def get_current_user (self): return self. session. get ("user_name") provided by tornado ")

Are you satisfied with this? Oh, I finally understood it !... Hello, what about the spirit of zuo (si? The key lies in session. py! You looked back at your head ....

First, check the required database:
Pickle: a database used for serialization and deserialization? You can directly look at the same effect as json ...)
Hmac and hashlib are used to generate encryption strings.
Uuid is used to generate a unique id
Memcache Python Client

There are three classes, SessionData Session and SessionManager. First look at the simplest SessionData.
SessionData is used to store session data in a dictionary structure. It inherits from the dictionary and only has two member variables more than the dictionary:

# Inherit the dictionary, because session access is similar to the dictionary class SessionData (dict): # The session id and hmac_key def _ init _ (self, session_id, hmac_key) are provided during initialization: self. session_id = session_id self. hmac_key = hmac_key


Then there is the real Session class. The Session class inherits from SessionData. Note that it is very similar to the built-in type dictionary. It only overwrites its own initialization method and defines the save interface-used to save the modified session data.

# Inherit SessionData class Session (SessionData): # initialize, bind the corresponding handler def _ init _ (self, session_manager, request_handler) of session_manager and tornado: self. session_manager = session_manager self. request_handler = request_handler try: # normally, all data of the session is obtained. Save current_session = session_manager.get (request_handler) into T InvalidSessionException as SessionData: # If it is the first access, an exception is thrown, when an exception occurs, an empty SessionData object is obtained, which contains no data, but contains the newly generated # session_id and hmac_key current_session = session_manager.get () # retrieves the data in current_session, iteratively save for key, data in current_session.iteritems (): self [key] = data # Save session_id self. session_id = current_session.session_id # and the corresponding hmac_key self. hmac_key = current_session.hmac_key # defines the save Method for saving the modified session. The set method def save (self) of session_manager is actually called. session_manager.set (self. request_handler, self)


The _ init _ method is hard to understand. The basic process is to define your own session_manager and handler to process objects. Then, use session_manager to obtain the existing session data and use the data to initialize a user's session. If this is the first access, the user obtains a new SessionData object, because it may be a new user, we need to assign values to session_id and hmac_key.
The save method provides an interface for saving session data after modification. It actually calls the set Method of session_manager. The specific implementation is not considered first.

When you see these two classes, you should have a basic understanding of the work of the session, which can be considered from the user access process. Pay attention to the BaseHandler entry. each user's access is an HTTP request. When the user's first access or the last session expires, tornado creates a handler object during the user's access (the handler must inherit from BaseHandler ), A session object is created during initialization. Because it is a new access, there is no data in the session currently, afterwards, the session is read and written in the form of a key/value pair (do not forget all the operations in which the Session has a dictionary). After modification, the session is saved using the save method. If the user is not new, the above process is followed. However, during session Initialization, the previous data is retrieved and saved in the instance. When the user ends the access, HTTP is disconnected, the handler instance is destroyed, and the session instance is destroyed (note that the instance is destroyed, not the data is destroyed ).

Let's talk about SessionManager ~ View functions one by one ~

The first step is initialization. Set the key, memcache address, and session Timeout time.

# The initialization requires a secret for session Encryption, memcache address, and session expiration time def _ init _ (self, secret, memcached_address, session_timeout): self. secret = secret self. memcached_address = memcached_address self. session_timeout = session_timeout

The _ fetch method is used to extract data from memcached with session_id as the key and parse the data using pickle deserialization:

# This method uses session_id to retrieve data from memcache def _ fetch (self, session_id): try: # connect to the memcache server mc = memcache. client (self. memcached_address, debug = 0) # obtain data session_data = raw_data = mc. get (session_id) if raw_data! = None: # to refresh timeout mc again. replace (session_id, raw_data, self. session_timeout, 0) # deserialize session_data = pickle. loads (raw_data) # if the obtained data is in the dictionary format, if type (session_data) = type ({}): return session_data else: return {} Handle t IOError: return {}


After security check, get returns memcached data (_ fetch called) in the form of SessionData.

Def get (self, request_handler = None): # obtain the session_id and hmac_key if (request_handler = None): session_id = None hmac_key = None else: # The session is based on cookie session_id = request_handler.get_secure_cookie ("session_id") hmac_key = request_handler.get_secure_cookie ("verification ") # if session_id does not exist, a new session_id and hmac_key if session_id = None: session_exists = False session_id = self are generated. _ ge Nerate_id () hmac_key = self. _ generate_hmac (session_id) else: session_exists = True # Check hmac_key check_hmac = self. _ generate_hmac (session_id) # if it fails, an exception is thrown! = Check_hmac: raise InvalidSessionException () # create a SessionData object session = SessionData (session_id, hmac_key) if session_exists: # obtain all session data session_data = self in memcache using the _ fetch method. _ fetch (session_id) for key, data in session_data.iteritems (): session [key] = data return session


The set method is used to update memcached data.

# To set a new session, set handler's cookie and memcache client def set (self, request_handler, session): # set the browser's cookie request_handler.set_secure_cookie ("session_id", session. session_id) request_handler.set_secure_cookie ("verification", session. hmac_key) # Use pickle to serialize session_data = pickle. dumps (dict (session. items (), pickle. HIGHEST_PROTOCOL) # connect to the memcache server mc = memcache. client (self. memcached_address, debug = 0) # Write to memcache mc. set (session. session_id, session_data, self. session_timeout, 0)


The last two functions generate session_id, And the other uses session_id and the key to encrypt and generate an encrypted string for verification.

# Generate session_id def _ generate_id (self): new_id = hashlib. sha256 (self. secret + str (uuid. uuid4 () return new_id.hexdigest () # generate hmac_key def _ generate_hmac (self, session_id): return hmac. new (session_id, self. secret, hashlib. sha256 ). hexdigest ()

Where did we initialize SessionManager? Do you still remember the Application class in the first article? Oh... go back and flip it.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.