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
webpy使用笔记(二) session/sessionid的使用的更多相关文章
- .net学习笔记----会话状态Session
一.会话状态Session Session用于服务器端状态管理,使用Session之后,每个客户端都可以将实际的数据保存在服务器上,对于每个客户端的数据,将会生成一个对应的唯一的key(保存在客户端) ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- Django day14(二) Session
Session 1. Session干什么用的? 解决cookie不安全的问题, 2. 原理是: 1) 存在服务器上的键值对{'sdaf随机字符串':{name:prince,pwd:123}} 2 ...
- tensorflow学习笔记二:入门基础 好教程 可用
http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础 TensorFlow用张量这种数据结构来表示所有的数据.用一 ...
- MyBatis笔记二:配置
MyBatis笔记二:配置 1.全局配置 1.properites 这个配置主要是引入我们的 properites 配置文件的: <properties resource="db.pr ...
- MZY项目笔记:session歧路
from my typora MZY项目笔记:session歧路 文章目录 MZY项目笔记:session歧路 那该怎么办? 1. 手动加上cookie的header. 2.自己模拟一个Session ...
- 用ILSpy查看Session.SessionID的生成算法
缘由 asp.net Session在InProc模式下,容易丢失,经常需要重新登录,且不支持分布式共享. 所以在研究Redis实现原生的Session,本来想用GUID作为key存入cookie,又 ...
- HttpContext.Current.Session.SessionID相关问题及备忘
今天Tony提到说我们系统中会利用如下代码来判断用户是否过期. if (string.IsNullOrEmpty(UserContext.ConnectionSessionId)) { LogUIFa ...
- 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX
<CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...
随机推荐
- 理解angularjs的作用域
<!doctype html> <html ng-app="myApp"> <head> <script src="http:/ ...
- python面向对象个人总结
基础概念:面向对象其实就是类与对象的使用. 类是模板,对象是实例.模板创建实例,实例去类里面去执行类的方法.类的例子: class Foo: def Bar(self): ...
- bind的用处
刚做的项目,遇到过这样的问题,就是在动态追加标签时,给追加的标签添加事件时,在标签内追加不了,后来使用了delegate代理,能响应了,但也是不能给动态追加的代理 $("body" ...
- 【DIOCP知识库】连接上下文TIocpClientContext
来自弦子介绍 [概述] 该类管理远程连接,每一个远程连接会对应一个该类的实例,开发时可以通过继承该类,扩展属性,可以存储更多的连接信息,可以重写OnRecvBuffer方法进行数据逻辑的处理 [字段/ ...
- ( 解压缩版 免安装版 或 zip版 )如何修改mysql5.6.24 字符编码
1.当我们把zip文件格式解压到指定目录后,并且完成基本环境配置后,打开mysql 5.6.24会发现名为[my-default.ini]的文件.我们用记事本打开该文件会发现并没有[default-c ...
- 《Cracking the Coding Interview 》之 二叉树的创建 与 遍历(非递归+递归version)
#include <iostream> #include <cstdio> #include <vector> #include <stack> #de ...
- umf(转)
深入浅出Eclipse Modeling Framework (EMF) Eclipse Modeling Framework (EMF),简单的说,就是Eclipse提供的一套建模框架,可以用EMF ...
- iOS真机调试问题-App installation failed,The maximum number of apps for free development profiles has been reached.
The maximum number of apps for free development profiles has been reached. 源引:http://www.jianshu.com ...
- Unity(一)介绍与基本使用
一.IOC介绍 IOC(Inversion of Control),中文译为控制反转,又称为“依赖注入”(DI =Dependence Injection) IOC的基本概念是:不创建对象,但是描述创 ...
- MYSQL存储过程:批量更新数据2(产品品牌)
执行语句 DELIMITER $$ DROP PROCEDURE IF EXISTS jsjh_goods_property_value_update$$ CREATE PROCEDURE jsjh_ ...