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的使用的更多相关文章

  1. .net学习笔记----会话状态Session

    一.会话状态Session Session用于服务器端状态管理,使用Session之后,每个客户端都可以将实际的数据保存在服务器上,对于每个客户端的数据,将会生成一个对应的唯一的key(保存在客户端) ...

  2. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  3. Django day14(二) Session

     Session 1. Session干什么用的? 解决cookie不安全的问题, 2. 原理是: 1) 存在服务器上的键值对{'sdaf随机字符串':{name:prince,pwd:123}} 2 ...

  4. tensorflow学习笔记二:入门基础 好教程 可用

    http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础   TensorFlow用张量这种数据结构来表示所有的数据.用一 ...

  5. MyBatis笔记二:配置

    MyBatis笔记二:配置 1.全局配置 1.properites 这个配置主要是引入我们的 properites 配置文件的: <properties resource="db.pr ...

  6. 用ILSpy查看Session.SessionID的生成算法

    缘由 asp.net Session在InProc模式下,容易丢失,经常需要重新登录,且不支持分布式共享. 所以在研究Redis实现原生的Session,本来想用GUID作为key存入cookie,又 ...

  7. HttpContext.Current.Session.SessionID相关问题及备忘

    今天Tony提到说我们系统中会利用如下代码来判断用户是否过期. if (string.IsNullOrEmpty(UserContext.ConnectionSessionId)) { LogUIFa ...

  8. 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  9. jQuery源码笔记(二):定义了一些变量和函数 jQuery = function(){}

    笔记(二)也分为三部分: 一. 介绍: 注释说明:v2.0.3版本.Sizzle选择器.MIT软件许可注释中的#的信息索引.查询地址(英文版)匿名函数自执行:window参数及undefined参数意 ...

随机推荐

  1. java web filter 学习(2)

    本文主要对filter的基本使用进行了讲解,其中涉及到了 filter是什么 一个filter处理一个jsp 多个filter处理一个jsp filter是什么 Filter 是java下的一种过滤器 ...

  2. 【洛谷P1196】银河英雄传说

    有特殊意义的一道题-- 加权并查集,我们增加cnt.deep数组 分别表示i点所在链共有多少个点,以及路径压缩之前点i在链中的深度 每次合并时直接修改cnt,路径压缩的同时更新deep 因为每次查询之 ...

  3. poj 1986 Distance Queries LCA

    题目链接:http://poj.org/problem?id=1986 Farmer John's cows refused to run in his marathon since he chose ...

  4. JVM基础知识总结

    因为没深入搞底层研究,所以也就没做很细致的笔记.相关笔记内容是直接从度娘那儿来的,重新删减.整理和加了点自己的东西. 1.JVM(Java Virtual Machine)是什么:JVM是一种用于计算 ...

  5. Unicode解码、URL编码/解码

    + (NSString *) stringByReplaceUnicode:(NSString *)string { NSMutableString *convertedString = [strin ...

  6. javascript keycode

    keycode    8 = BackSpace BackSpacekeycode    9 = Tab Tabkeycode   12 = Clearkeycode   13 = Enterkeyc ...

  7. BZOJ_3685_普通van Emde Boas树_权值线段树

    BZOJ_3685_普通van Emde Boas树_权值线段树 Description 设计数据结构支持: 1 x  若x不存在,插入x 2 x  若x存在,删除x 3    输出当前最小值,若不存 ...

  8. Hadoop开启后jps显示只有jps

    之前在用Mapreduce写代码时,在DFS Location下的会报一个error,大体的意思就是与主机名相关的错误 然后我就觉得可能时Hadoop开启时出了错误,然后我就重启了Hadoop,jps ...

  9. PHPUnit实践一(初识)

    PHPUnit实践一(初识)     本系列教程所有的PHPUnit测试基于PHPUnit6.5.9版本,Lumen 5.5框架 前置 日常我们的普通用到的测试: 代码直接echo,debug等方法测 ...

  10. BZOJ4321queue2——DP/递推

    题目描述 n 个沙茶,被编号 1~n.排完队之后,每个沙茶希望,自己的相邻的两 人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行:  现在想知道,存在多少方案满足沙茶们如此不苛刻的条件. ...