python cgi 实现用户会话

众所周知,http协议是无状态的,也就是说客户端每次连接到服务器时,都是一个全新的状态,上一次访问服务器的状态无法在当次访问中维持,在B/S应用开发中,通常使用Cookie保存客户端状态,Cookies最典型的应用是判定注册用户是否已经登录网站,用户可能会得到提示,是否在下一次进入此网站时保留用户信息以便简化登录手续,这些都是
Cookies的功用。另一个重要应用场合是“购物车”之类处理。用户可能会在一段时间内在同一家网站的不同页面中选择不同的商品,这些信息都会写入
Cookies,以便在最后付款时提取信息。而后来的http会话(session)机制则是提供了另一种在服务器和客户端之间保持状态同步的方法,于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的。
PHP、ASP都提供了较方面的方法创建和管理Session,Python的cgi模块却没有,在作一些简单的应用时,可以通过一些简单的方法手动实现Session的创建和管理。具体步骤如下:
1,在用户登录时,随机生成会话标识,同时保存在服务器端和客户端Cookie中;
2,用户登录完成后的每次访问,检查客户端Cookie中的会话标识,与服务器中的会话标识比较,以确定用户是否已登录;
3,用户退出登录后,清除客户端Cookie中的会话标识及服务器端的会话标识,退出会话。
下面是登录页面的部份代码:
#!/usr/bin/python
# -*- coding: utf8 -*-
import sys,os,cgi,MySQLdb,random,sha,Cookie
from option import *
def check_login(username,password):
    global data_server,server_username,server_password,database_name
    try:
        conn=MySQLdb.connect(host=data_server,user=server_username,passwd=server_password,db=database_name)
        conn.set_character_set('UTF8')
    except Exception,e:
        print e
        sys.exit()
    cursor=conn.cursor()
    sql='SELECT id FROM user_man WHERE login_name LIKE "%s" AND password LIKE "%s"' %(username,password)
    cursor.execute(sql)
    ss=cursor.fetchall()
    if ss:
        userid=ss[0][0]
        cursor.close()
        save_session(userid)
        return 1
    else:
        cursor.close()
        return 0
def save_session(userid):
#使用随机数生成64位SHA会话标识!
    sha_session=sha.new()
    sha_session.update(str(random.random()))
    session_str=sha_session.hexdigest()
##保存会话标识到服务器!!
    try:
        conn=MySQLdb.connect(host=data_server,user=server_username,passwd=server_password,db=database_name)
        conn.set_character_set('UTF8')
    except Exception,e:
        print e
        sys.exit()
    cursor=conn.cursor()
    session_cookie=session_str
    sql='UPDATE user_man SET session="%s" WHERE id=%d' %(session_str,userid)
    cursor.execute(sql)   
    cursor.close()
#保存会话标识到客户端Cookie!
    c = Cookie.SimpleCookie()
    c['userid']=str(userid)
    c['session']=str(session_cookie)
    print c.output()
    del sha_session
#函数test_login()可以放到其实需要登录使用的页面中,用于识别会话是否建立,是否需要重新登录
def test_login():
    global data_server,server_username,server_password,database_name
    c=Cookie.SimpleCookie(os.environ.get("HTTP_COOKIE"))
    remote_userid=c.get("userid")
    session_cookie=c.get("session")
    if (remote_userid is None) or (session_cookie is None):
        return None
    else:
#check session valaid!
        try:
            conn=MySQLdb.connect(host=data_server,user=server_username,passwd=server_password,db=database_name)
            conn.set_character_set('UTF8')
        except Exception,e:
            print e
            return None
        cursor=conn.cursor()
        sql='SELECT session FROM user_man WHERE id=%s' %(remote_userid.value)
        cursor.execute(sql)
        ss=cursor.fetchall()
        if ss:
            session_db=ss[0][0]
            if session_db==session_cookie.value:
                cursor.close()
                return remote_userid.value
        else:
            cursor.close()
            return None
            
#比如在一个页面中检查会话以确定是否需要重新登录,可以这样写:
def main():
    print "Content-Type: text/html\n\n"
    login_name=test_login()
    if login_name is None:
        redirect("/login.py","您尚未登录,3秒后将自动转到登录窗口!","错误!",3)
        sys.exit()
    else:
        print_html_content()
#如果会话不存在,则自动跳转到登录页面。