cookie

1、基本操作

Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)

在后台设置cookie:

class IndexHanlder(tornado.web.RequestHandler):
    def get(self):
        print(self.cookies) #获取http请求中携带的浏览器中的所有cookie
        print(self.get_cookie("k1"))  # 获取浏览器中的cooki
        self.set_cookie("k1","v1")  #为浏览器设置cookie

在前端(浏览器上使用JavaScript):

document.cookie               #获取浏览器中所有的cookie
document.cookie.split(";")   #获取浏览器中具体某一个cookie,需要先分割,再操作
document.cookie = "k1=999"   #设置cookie

由于Cookie保存在浏览器端,所以在浏览器端也可以使用JavaScript来操作Cookie:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>123</h1>
</body>
<script>
/*设置cookie,指定秒数过期*/
function setCookieBySeconds(name,value,expires){
    var current_date = new Date();  //获取当前时间
    current_date.setSeconds(current_date.getSeconds() + expires);
    document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
}
/*设置cookie,指定天数过期*/
function setCookieByDays(name,value,expires){
    var current_date = new Date();  //获取当前时间
    current_date.setDate(current_date.getDate() + expires);
    document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
}
</script>
</html>

2、加密cookie(签名)

Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中: 

def _create_signature_v1(secret, *parts):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
    for part in parts:
        hash.update(utf8(part))
    return utf8(hash.hexdigest())

# 加密
def _create_signature_v2(secret, s):
    hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)
    hash.update(utf8(s))
    return utf8(hash.hexdigest())

def create_signed_value(secret, name, value, version=None, clock=None,
                        key_version=None):
    if version is None:
        version = DEFAULT_SIGNED_VALUE_VERSION
    if clock is None:
        clock = time.time

    timestamp = utf8(str(int(clock())))
    value = base64.b64encode(utf8(value))
    if version == 1:
        signature = _create_signature_v1(secret, name, value, timestamp)
        value = b"|".join([value, timestamp, signature])
        return value
    elif version == 2:
        # The v2 format consists of a version number and a series of
        # length-prefixed fields "%d:%s", the last of which is a
        # signature, all separated by pipes.  All numbers are in
        # decimal format with no leading zeros.  The signature is an
        # HMAC-SHA256 of the whole string up to that point, including
        # the final pipe.
        #
        # The fields are:
        # - format version (i.e. 2; no length prefix)
        # - key version (integer, default is 0)
        # - timestamp (integer seconds since epoch)
        # - name (not encoded; assumed to be ~alphanumeric)
        # - value (base64-encoded)
        # - signature (hex-encoded; no length prefix)
        def format_field(s):
            return utf8("%d:" % len(s)) + utf8(s)
        to_sign = b"|".join([
            b"2",
            format_field(str(key_version or 0)),
            format_field(timestamp),
            format_field(name),
            format_field(value),
            b''])

        if isinstance(secret, dict):
            assert key_version is not None, 'Key version must be set when sign key dict is used'
            assert version >= 2, 'Version must be at least 2 for key version support'
            secret = secret[key_version]

        signature = _create_signature_v2(secret, to_sign)
        return to_sign + signature
    else:
        raise ValueError("Unsupported version %d" % version)

# 解密
def _decode_signed_value_v1(secret, name, value, max_age_days, clock):
    parts = utf8(value).split(b"|")
    if len(parts) != 3:
        return None
    signature = _create_signature_v1(secret, name, parts[0], parts[1])
    if not _time_independent_equals(parts[2], signature):
        gen_log.warning("Invalid cookie signature %r", value)
        return None
    timestamp = int(parts[1])
    if timestamp < clock() - max_age_days * 86400:
        gen_log.warning("Expired cookie %r", value)
        return None
    if timestamp > clock() + 31 * 86400:
        # _cookie_signature does not hash a delimiter between the
        # parts of the cookie, so an attacker could transfer trailing
        # digits from the payload to the timestamp without altering the
        # signature.  For backwards compatibility, sanity-check timestamp
        # here instead of modifying _cookie_signature.
        gen_log.warning("Cookie timestamp in future; possible tampering %r",
                        value)
        return None
    if parts[1].startswith(b"0"):
        gen_log.warning("Tampered cookie %r", value)
        return None
    try:
        return base64.b64decode(parts[0])
    except Exception:
        return None


def _decode_fields_v2(value):
    def _consume_field(s):
        length, _, rest = s.partition(b':')
        n = int(length)
        field_value = rest[:n]
        # In python 3, indexing bytes returns small integers; we must
        # use a slice to get a byte string as in python 2.
        if rest[n:n + 1] != b'|':
            raise ValueError("malformed v2 signed value field")
        rest = rest[n + 1:]
        return field_value, rest

    rest = value[2:]  # remove version number
    key_version, rest = _consume_field(rest)
    timestamp, rest = _consume_field(rest)
    name_field, rest = _consume_field(rest)
    value_field, passed_sig = _consume_field(rest)
    return int(key_version), timestamp, name_field, value_field, passed_sig


def _decode_signed_value_v2(secret, name, value, max_age_days, clock):
    try:
        key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value)
    except ValueError:
        return None
    signed_string = value[:-len(passed_sig)]

    if isinstance(secret, dict):
        try:
            secret = secret[key_version]
        except KeyError:
            return None

    expected_sig = _create_signature_v2(secret, signed_string)
    if not _time_independent_equals(passed_sig, expected_sig):
        return None
    if name_field != utf8(name):
        return None
    timestamp = int(timestamp)
    if timestamp < clock() - max_age_days * 86400:
        # The signature has expired.
        return None
    try:
        return base64.b64decode(value_field)
    except Exception:
        return None


def get_signature_key_version(value):
    value = utf8(value)
    version = _get_version(value)
    if version < 2:
        return None
    try:
        key_version, _, _, _, _ = _decode_fields_v2(value)
    except ValueError:
        return None

    return key_version
View Code

五、Session(依赖于cookie)

由于cookie中需要保存客户的很多信息,而且如果信息很多的话,服务端与客户端交互的时候也浪费流量,所以我们需要用很少的一段字符串来保存很多的信息,这就是我们所要引进的session。

cookie 和session 的区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗    考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能    考虑到减轻服务器性能方面,应当使用COOKIE。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、所以个人建议:    将登陆信息等重要信息存放为SESSION    其他信息如果需要保留,可以放在COOKIE中

  (1)利用session实现用户验证

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.web
import tornado.ioloop
import hashlib
import time
li = {}
class IndexHanlder(tornado.web.RequestHandler):
    def get(self):
        obj = hashlib.md5()
        obj.update(bytes(str(time.time()),encoding="utf-8"))
        random_str = obj.hexdigest()
        li[random_str]={}
        li[random_str]["k1"]=123
        li[random_str]["k2"]=456
        li[random_str]["is_login"]=True
        self.set_cookie("qqqqqq",random_str)
        self.write("成功设置cookie")
    def post(self, *args, **kwargs):
        pass

class ManagerHanlder(tornado.web.RequestHandler):
    def get(self):
        random_str = self.get_cookie("qqqqqq",None)
        current_user_info = li.get(random_str,None)
        if not current_user_info:
            self.redirect("/index")
        else:
            if li[random_str]["is_login"]:
                self.write("欢迎")
            else:
                self.redirect("/index")
        def post(self, *args, **kwargs):
            pass

settings={
    "template_path":"tpl",
     "static_path":"st",
    "cookie_secret":"123"
}

class IndeHanlder(tornado.web.RequestHandler):
    def get(self):
        self.render("1.html")
application = tornado.web.Application([
    (r"/index", IndexHanlder),
    (r"/manager", ManagerHanlder),
],**settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

 (2)利用session验证用户精简版

#!/usr/bin/env/python
# -*- coding:utf-8 -*-
import tornado.web

container = {}
# container = {
#     # "第一个人的随机字符串":{},
#     # "第一个人的随机字符串":{'k1': 111, 'parents': '你'},
# }

class Session:
    def __init__(self, handler):
        self.handler = handler
        self.random_str = None

    def __genarate_random_str(self):
        import hashlib
        import time
        obj = hashlib.md5()
        obj.update(bytes(str(time.time()), encoding='utf-8'))
        random_str = obj.hexdigest()
        return random_str

    def __setitem__(self, key, value):
        # 在container中加入随机字符串
        # 定义专属于自己的数据
        # 在客户端中写入随机字符串
        # 判断,请求的用户是否已有随机字符串
        if not self.random_str:
            random_str = self.handler.get_cookie('__kakaka__')
            if not random_str:
                random_str = self.__genarate_random_str()
                container[random_str] = {}
            else:
                # 客户端有随机字符串
                if random_str in container.keys():
                    pass
                else:
                    random_str = self.__genarate_random_str()
                    container[random_str] = {}
            self.random_str = random_str 

        container[self.random_str][key] = value
        self.handler.set_cookie("__kakaka__", self.random_str)

    def __getitem__(self, key):
        # 获取客户端的随机字符串
        # 从container中获取专属于我的数据
        #  专属信息【key】
        random_str =  self.handler.get_cookie("__kakaka__")
        if not random_str:
            return None
        # 客户端有随机字符串
        user_info_dict = container.get(random_str,None)
        if not user_info_dict:
            return None
        value = user_info_dict.get(key, None)
        return value
class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = Session(self)
class IndexHandler(BaseHandler):
    def get(self):
        if self.get_argument('u',None) in ['alex','eric']:
            self.session['is_login'] = True
            self.session['name'] =self.get_argument('u',None)
            print(container)
        else:
            self.write('请你先登录')
class MangerHandler(BaseHandler):
    def get(self):
        val = self.session['is_login']
        if val:
            self.write(self.session['name'])
        else:
            self.write('登录失败')
class LoginHandler(BaseHandler):
    def get(self,*args,**kwargs):
        self.render('login.html',status="")
    def post(self, *args, **kwargs):
        user = self.get_argument('user',None)
        pwd = self.get_argument('pwd',None)
        code = self.get_argument('code',None)
        check_code = self.session['CheckCode']
        if code.upper() == check_code.upper():
            self.write('验证码正确')
        else:
            self.render('login.html',status ='验证码错误')
class CheckCodeHandler(BaseHandler):
    def get(self,*args,**kwargs):
        import io
        import check_code
        mstream = io.BytesIO()
        img, code = check_code.create_validate_code()
        img.save(mstream,'GIF')
        self.session['CheckCode']=code
        self.write(mstream.getvalue())
class CsrfHandler(BaseHandler):
    def get(self,*args,**kwargs):
        self.render("csrf.html")
    def post(self, *args, **kwargs):
        self.write("hahahahaah")

settings = {
    'template_path':'views',
    'static_path':'static',
    "xsrf_cookies":True
}
application = tornado.web.Application([
    (r'/index',IndexHandler),
    (r'/manger',MangerHandler),
    (r'/login',LoginHandler),
    (r'/check_code',CheckCodeHandler),
    (r'/csrf',CsrfHandler),
],**settings)

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

  

 

原文地址:https://www.cnblogs.com/guokaixin/p/5832190.html