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

本文发布时间: 2019-Mar-22
webpy使用笔记(二) session的使用  webpy使用系列之session的使用,虽然工作中使用的是django,但是自己并不喜欢那种大而全的东西~什么都给你准备好了,自己好像一个机器人一样赶着重复的基本工作,从在学校时候就养成了追究原理的习惯,从而有了这篇session的使用和说明。  PS:其实有些总结的东西挺好的,想分享给大家看,而不是枯燥的代码,这东西说实话对其他人用处不大,但都被移除首页了~~webpy中的session  下面为官方的例子,用session来存储页面访问的次数,从而实现对访问次数的记录。  (PS,这里记录是针对一个客户端来说的访问次数,而不是官方文档说的统计有多少人正在使用session,因为每个客户端的session并不相同,服务器会根据不同的sessionid来区分不同的客户端的session)  需要注意的是,官方说明在调试情况下,session并不能正常的运行,所以需要在非调试摸下测试,那么就有了下面的这个例子。import web#非调试模式web.config.debug = Falseurls = ( '/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 weburls = ('/', '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 = sessionelse: session = web.config._sessionclass hello: def GET(self): print 'session', session session.count += 1 return 'Hello, %s!' % session.countif __name__ == '__main__': app.run()  由于web.session.Session会重载两次,但是在上面的_session并不会重载两次,因为上面多了一个判断_session是否存在于web.config中。  其实,在web.py文件中,定义了config,而Storage在下面的图中并没有特殊的结果,像字典一样~#web.pyconfig = storage()#utils.pystorage = 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.pydef session_hook():  web.ctx.session = sessionapp.add_processor(web.loadhook(session_hook))#views.pyclass 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 = TrueSession类  在webpy的session中,存储方式包括两种DiskStore和DBStore,分别为硬盘存储和数据库存储。      而session的存储也可以看出来,把sessionid作为key来存储session信息


(以上内容不代表本站观点。)
---------------------------------
本网站以及域名有仲裁协议。
本網站以及域名有仲裁協議。

2024-Mar-04 02:10pm
栏目列表