python webpy 获取ip_webpy使用笔记(二) session/sessionid的使用

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

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

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

webpy中的session

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

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

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

importweb

#非调试模式

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})classcount:defGET(self):

session.count+= 1

returnstr(session.count)classreset:defGET(self):

session.kill()return ""

if __name__ == "__main__":

app.run()

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

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

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

importweb

urls= ("/", "hello")

app=web.application(urls, globals())if web.config.get('_session') isNone:

session= web.session.Session(app, web.session.DiskStore('sessions'), {'count': 0})

web.config._session=sessionelse:

session=web.config._sessionclasshello:defGET(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.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()。

defmy_loadhook():print "my load hook"

defmy_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

defsession_hook():

web.ctx.session=session

app.add_processor(web.loadhook(session_hook))#views.py

classedit:defGET(self):try:

session=web.ctx.session

username=session.usernameif notusername:return web.redirect('/login')exceptException 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的方式存储,

classSession(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__

ifapp:

app.add_processor(self._processor)def __contains__(self, name):return name inself._datadef __getattr__(self, name):returngetattr(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:returnhandler()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 notself._valid_session_id(self.session_id):

self.session_id=None

self._check_expiry()ifself.session_id:

d=self.store[self.session_id]

self.update(d)

self._validate_ip()if notself.session_id:

self.session_id=self._generate_session_id()ifself._initializer:ifisinstance(self._initializer, dict):

self.update(deepcopy(self._initializer))elif hasattr(self._initializer, '__call__'):

self._initializer()

self.ip=web.ctx.ipdef_check_expiry(self):#check for expiry

if self.session_id and self.session_id not inself.store:ifself._config.ignore_expiry:

self.session_id=Noneelse:returnself.expired()def_validate_ip(self):#check for change of IP

if self.session_id and self.get('ip', None) !=web.ctx.ip:if notself._config.ignore_change_ip:returnself.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"""

whileTrue:

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 inself.store:break

returnsession_iddef_valid_session_id(self, session_id):

rx= utils.re_compile('^[0-9a-fA-F]+$')returnrx.match(session_id)def_cleanup(self):"""Cleanup the stored sessions"""current_time=time.time()

timeout=self._config.timeoutif current_time - self._last_cleanup_time >timeout:

self.store.cleanup(timeout)

self._last_cleanup_time=current_timedefexpired(self):"""Called when an expired session is atime"""self._killed=True

self._save()raiseSessionExpired(self._config.expired_message)defkill(self):"""Kill the session, make it no longer available"""

delself.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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值