第6节,tornado 如何使用cookie

关于cookie在web工程中的作用请阅读我的另一篇文章flask web开发中使用cookie,本文不对cookie概念再做介绍,而是专注于讲解tornado中如何使用cookie

1. set_cookie 与 get_cookie

在tornaod中设置cookie值使用set_cookie方法,使用get_cookie获取cookie值,下面的例子将使用cookie保存不同用户上一次的访问时间

from datetime import datetime, timedelta
import tornado.ioloop
from tornado.web import RequestHandler, Application
from tornado.httpserver import HTTPServer
from tornado.options import options, define

define('port', default=8000, help='监听端口')


class HelloHandler(RequestHandler):
    def get(self, name):
        last_access_time = self.get_cookie(name)
        self.set_cookie(name, datetime.now().strftime("%Y-%m-%dT%H:%M:%S"))
        if last_access_time:
            self.finish(f'welcome {name}, you last access time is {last_access_time}')
        else:
            self.finish(f'welcome {name} you access this web first time')


if __name__ == '__main__':
    options.parse_command_line()
    handlers_routes = [
        (r'/(.*)', HelloHandler)
    ]
    app = Application(handlers=handlers_routes)
    http_server = HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

在设置cookie值时,我将时间转为“2021-11-11T19:18:46”, 在日期与小时之间有一个T,之所以这样做是因为tornado 会对cookie的值进行检查,如果cookie的value里包含ascii码里的前32个字符中的任意一个,则视为违法字符,对于key也是如此

    name = escape.native_str(name)
    value = escape.native_str(value)
    if re.search(r"[\x00-\x20]", name + value):
        # Don't let us accidentally inject bad stuff
        raise ValueError("Invalid cookie %r: %r" % (name, value))

这样做的目的是为了预防XSS攻击,因此我不得不去掉时间字符串里的空格符,中间加一个T,这种格式是ISO 8601,后面应该加一个Z表示UTC时间,如果是北京时间则应该加“+0800”,这里我给省略了。

2. 设置过期时间

2.1 通过max_age 设置过期时间

self.set_cookie(name, datetime.now().strftime("%Y-%m-%dT%H:%M:%S"), max_age=5)

max_age参数设置多少秒以后cookie过期,这是一个非常简便的设置过期的方法

2.2 通过expires 设置过期时间

expires 可以指定过期时间,这样可以精准的指定在某个特定的时间点过期

expires_time = datetime(year=2021, month=11, day=12, hour=18) - timedelta(hours=8)
        self.set_cookie(name, datetime.now().strftime("%Y-%m-%dT%H:%M:%S"), expires=expires_time)

我希望cookie的过期时间设置在11月12号的18点,但expires要求传入的是UTC时间,因此我要在这个时间基础上减去8小时得到UTC时间。除了expires参数,还可以使用expires_days传入过期的天数,当expires没没有传值而expires_days有值传入时则将过期时间设置为当前UTC时间加上expires_days以后的时间。如果两个参数都不传,则默认过期时间为30天。

设置安全的cookie

cookie的值可以在浏览器里查看,是可以被伪造的,如果你很在意cookie的安全性,可以使用set_secure_cookie方法设置cookie,使用此方法需要在创建application的时候设置cookie_secret 秘钥

app = Application(handlers=handlers_routes, cookie_secret='hard to guess')

获取cookie值的方法也要使用安全的get_secure_cookie

class HelloHandler(RequestHandler):
    def get(self, name):
        last_access_time = self.get_secure_cookie(name)
        expires_time = datetime(year=2021, month=11, day=12, hour=18) - timedelta(hours=8)
        self.set_secure_cookie(name, datetime.now().strftime("%Y-%m-%dT%H:%M:%S"), expires=expires_time)
        if last_access_time:
            self.finish(f'welcome {name}, you last access time is {last_access_time}')
        else:
            self.finish(f'welcome {name} you access this web first time')

只要秘钥不被泄露,那么就没有人可以伪造出cookie值欺骗你的网站。

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案