zoukankan      html  css  js  c++  java
  • webpy使用笔记(二) session/sessionid的使用

    webpy使用笔记(二) session的使用

      webpy使用系列之session的使用,虽然工作中使用的是django,但是自己并不喜欢那种大而全的东西~什么都给你准备好了,自己好像一个机器人一样赶着重复的基本工作,从在学校时候就养成了追究原理的习惯,从而有了这篇session的使用和说明。

      PS:其实有些总结的东西挺好的,想分享给大家看,而不是枯燥的代码,这东西说实话对其他人用处不大,但都被移除首页了~~

    webpy中的session

      下面为官方的例子,用session来存储页面访问的次数,从而实现对访问次数的记录。

      (PS,这里记录是针对一个客户端来说的访问次数,而不是官方文档说的统计有多少人正在使用session,因为每个客户端的session并不相同,服务器会根据不同的sessionid来区分不同的客户端的session)

      需要注意的是,官方说明在调试情况下,session并不能正常的运行,所以需要在非调试摸下测试,那么就有了下面的这个例子。

    import web
    #非调试模式 web.config.debug
    = False urls = ( "/count", "count", "/reset", "reset" ) app = web.application(urls, locals()) session = web.session.Session(app, web.session.DiskStore('sessions'), initializer={'count': 0}) class count: def GET(self): session.count += 1 return str(session.count) class reset: def GET(self): session.kill() return "" if __name__ == "__main__": app.run()

       在官方文档中,对上述debug模式的现象给出了这样的解释:

      session与调试模试下的重调用相冲突(有点类似firefox下著名的Firebug插件,使用Firebug插件分析网页时,会在火狐浏览器之外单独对该网页发起请求,所以相当于同时访问该网页两次)

      为了解决上述问题,官方给出了进一步的解决方法,如下

    import web
    urls = ("/", "hello")
    
    app = web.application(urls, globals())
    
    if web.config.get('_session') is None:
        session = web.session.Session(app, web.session.DiskStore('sessions'), {'count': 0})
        web.config._session = session
    else:
        session = web.config._session
    
    class hello:
       def GET(self):
           print 'session', session
           session.count += 1
           return 'Hello, %s!' % session.count
    
    if __name__ == "__main__":
       app.run()

      由于web.session.Session会重载两次,但是在上面的_session并不会重载两次,因为上面多了一个判断_session是否存在于web.config中。

      其实,在web.py文件中,定义了config,而Storage在下面的图中并没有特殊的结果,像字典一样~

    #web.py
    config = storage()
    
    #utils.py
    storage = Storage

    在webpy的子程序中使用session

      虽然官方文档中提到,只能在主程序中使用session,但是通过添加__init__.py可以条用到该页面的session,也就是说一样使用session。

      官方给出的方法更加合理化一点,通过应用处理器,加载钩子(loadhooks)

      在webpy中,应用处理器为app.add_processor(my_processor),下面的代码添加到上述的完整例子中,可以再处理请求前和处理请求后分别条用my_loadhook()和my_unloadhook()。

    def my_loadhook():
        print "my load hook"
    
    def my_unloadhook():
        print "my unload hook"
    
    app.add_processor(web.loadhook(my_loadhook))
    app.add_processor(web.unloadhook(my_unloadhook))

    结果如下,我在处理中打印了session:

      从而,可以再web.loadhook()中加载session信息,在处理之前从web.ctx.session中获取session了,甚至可以在应用处理器中添加认证等操作。

    #main.py
    def session_hook():
      web.ctx.session = session
    app.add_processor(web.loadhook(session_hook))
    
    #views.py
    class edit:
        def GET(self):
            try:
                session = web.ctx.session
                username = session.username
                if not username:
                    return web.redirect('/login')
            except Exception as e:
                return web.redirect('/login')
            return render_template('edit.html')

    sessionid

      对于服务器来说,怎样才能区分不同客户端呢,怎样才能区分不同客户端的session呢?

      是通过sessionid来实现的,最初我还傻傻的分不清session和cookie,以及不同用户之间的信息室如何分配的!

      

      如上图,是生成sessionid的代码段,其中包含了随机数、时间、ip以及秘钥。

      在客户端访问服务器时,服务器会根据上述信息来计算一个针对客户端唯一的sessionid,并通过cookie保存在客户端中。

      客户端用cookie保存了sessionID,当我们请求服务器的时候,会把这个sessionID一起发给服务器,服务器会到内存中搜索对应的sessionID,如果找到了对应的 sessionID,说明我们处于登录状态,有相应的权限;如果没有找到对应的sessionID,这说明:要么是我们把浏览器关掉了(后面会说明为什 么),要么session超时了(没有请求服务器超过20分钟),session被服务器清除了,则服务器会给你分配一个新的sessionID。你得重新登录并把这个新的sessionID保存在cookie中。 

    session的结构

      上面提到了session在webpy中式一种dict的方式存储,

    class Session(object):
        """Session management for web.py
        """
        __slots__ = [
            "store", "_initializer", "_last_cleanup_time", "_config", "_data", 
            "__getitem__", "__setitem__", "__delitem__"
        ]
    
        def __init__(self, app, store, initializer=None):
            self.store = store
            self._initializer = initializer
            self._last_cleanup_time = 0
            self._config = utils.storage(web.config.session_parameters)
            self._data = utils.threadeddict()
            
            self.__getitem__ = self._data.__getitem__
            self.__setitem__ = self._data.__setitem__
            self.__delitem__ = self._data.__delitem__
    
            if app:
                app.add_processor(self._processor)
    
        def __contains__(self, name):
            return name in self._data
    
        def __getattr__(self, name):
            return getattr(self._data, name)
        
        def __setattr__(self, name, value):
            if name in self.__slots__:
                object.__setattr__(self, name, value)
            else:
                setattr(self._data, name, value)
            
        def __delattr__(self, name):
            delattr(self._data, name)
    
        def _processor(self, handler):
            """Application processor to setup session for every request"""
            self._cleanup()
            self._load()
    
            try:
                return handler()
            finally:
                self._save()
    
        def _load(self):
            """Load the session from the store, by the id from cookie"""
            cookie_name = self._config.cookie_name
            cookie_domain = self._config.cookie_domain
            cookie_path = self._config.cookie_path
            httponly = self._config.httponly
            self.session_id = web.cookies().get(cookie_name)
    
            # protection against session_id tampering
            if self.session_id and not self._valid_session_id(self.session_id):
                self.session_id = None
    
            self._check_expiry()
            if self.session_id:
                d = self.store[self.session_id]
                self.update(d)
                self._validate_ip()
            
            if not self.session_id:
                self.session_id = self._generate_session_id()
    
                if self._initializer:
                    if isinstance(self._initializer, dict):
                        self.update(deepcopy(self._initializer))
                    elif hasattr(self._initializer, '__call__'):
                        self._initializer()
     
            self.ip = web.ctx.ip
    
        def _check_expiry(self):
            # check for expiry
            if self.session_id and self.session_id not in self.store:
                if self._config.ignore_expiry:
                    self.session_id = None
                else:
                    return self.expired()
    
        def _validate_ip(self):
            # check for change of IP
            if self.session_id and self.get('ip', None) != web.ctx.ip:
                if not self._config.ignore_change_ip:
                   return self.expired() 
        
        def _save(self):
            if not self.get('_killed'):
                self._setcookie(self.session_id)
                self.store[self.session_id] = dict(self._data)
            else:
                self._setcookie(self.session_id, expires=-1)
                
        def _setcookie(self, session_id, expires='', **kw):
            cookie_name = self._config.cookie_name
            cookie_domain = self._config.cookie_domain
            cookie_path = self._config.cookie_path
            httponly = self._config.httponly
            secure = self._config.secure
            web.setcookie(cookie_name, session_id, expires=expires, domain=cookie_domain, httponly=httponly, secure=secure, path=cookie_path)
        
        def _generate_session_id(self):
            """Generate a random id for session"""
    
            while True:
                rand = os.urandom(16)
                now = time.time()
                secret_key = self._config.secret_key
                session_id = sha1("%s%s%s%s" %(rand, now, utils.safestr(web.ctx.ip), secret_key))
                session_id = session_id.hexdigest()
                if session_id not in self.store:
                    break
            return session_id
    
        def _valid_session_id(self, session_id):
            rx = utils.re_compile('^[0-9a-fA-F]+$')
            return rx.match(session_id)
            
        def _cleanup(self):
            """Cleanup the stored sessions"""
            current_time = time.time()
            timeout = self._config.timeout
            if current_time - self._last_cleanup_time > timeout:
                self.store.cleanup(timeout)
                self._last_cleanup_time = current_time
    
        def expired(self):
            """Called when an expired session is atime"""
            self._killed = True
            self._save()
            raise SessionExpired(self._config.expired_message)
     
        def kill(self):
            """Kill the session, make it no longer available"""
            del self.store[self.session_id]
            self._killed = True
    Session类

      在webpy的session中,存储方式包括两种DiskStore和DBStore,分别为硬盘存储和数据库存储。

      

      

      而session的存储也可以看出来,把sessionid作为key来存储session信息

      

    参考

    http://doc.outofmemory.cn/python/webpy-cookbook/

    http://webpy.org/docs/0.3/tutorial

  • 相关阅读:
    如何配置wamp多站点主机
    一些类和对象问题的探索,简单易懂的命名空间及use的使用
    [4] Git使用流程
    [正则] JS常用正则
    [3] Django返回json数据
    [8] Eclipse各版本代号一览表以及官网上有很多版本的eclipse的比较
    [7] MySQL数据库--学生管理系统数据库设计
    [11]Docker02 Docker重要概念
    [12]Docker03 Centos7安装Docker
    [小程序]小程序环境搭建
  • 原文地址:https://www.cnblogs.com/coder2012/p/4077661.html
Copyright © 2011-2022 走看看