去年底接手公司某个项目,python语言、tornado框架;修修补补了解业务和代码逻辑之后,发现代码组织有些混乱,扩展性较差!所以推倒重构,花费很大精力和心思想要做到极致,差不多四个月时间开发测试通过。
本以为这是自己的代表作,奈何被断断续续报告的 “系统自动退出” 所折磨!真是想说一声:阿西八!
问题场景
- 首先认证登录系统,设置加密cookie,有效时长 90 天
- 系统用一段时间(绝没有90天)后,会自动退出,重定向到
/auth
认证页面
系统逻辑
系统使用前需要按照配置的认证信息进行认证登录,如果认证登录成功,程序会在浏览器设置三个cookie信息:park_code
、device_id
和device_sign
。在每次请求时检查这些信息是否在系统中存在,同时根据这些信息获取到对于账号的相关信息。如果没有获取到有效地这三个cookie信息,系统会认为没有认证过,自动跳转到认证页面,要求输入认证信息后继续操作。
问题追踪
- 期初以为是设置的 90 天过期,时间太短,OK!弄长点:365天! 发现依然问题存在
- 我在想是不是Windows系统垃圾清理清理掉了浏览器的cookie,但是这不合理啊,Windows系统又不是没有存储了,磁盘还有很多空闲,这个可能性不大
- 基于程序的逻辑,我去检查了浏览器上cookie信息,发现cookie信息存在!并且
Expires / Max-Age
过期时间一栏还早着呢 - 服务器端打印出每次请求获取到的cookie信息,发现都是
None
,为什么浏览器上有cookie,但是服务器就是获取不到呢?
源码分析
Tornado做为python主流框架,按理来说应该有丰富完整的文档,但是对于国内用户(特别是我这种小学英语毕业)来说:可用的、优秀的中文文档太少太少!还是直接上源码看吧,简单直接!
借助强大的IDE:vscode!追溯源码,快速跳转到定义简直了!
关于cookie
的相关源码主要都在 site-packages/tornado/web.py
文件中,阔以说看起来相当方便和简单,只是这个变态的文件代码真是多:足足 3318 行代码!所以不要一行一行看,你会累死的,你也会放弃的🤣 , 还是有问题去追溯比较好!
我们的问题所用到的方法只有两个:set_secure_cookie
和 get_secure_cookie
;设置cookie和获取cookie,看看tornado如何操作cookie的:
- web.py: 590行
set_secure_cookie()
-调用最关键->create_signed_value()
方法生成加密值,下面是我摘取源码的测试脚本,看注释啦
1 |
|
- web.py 639行
get_secure_cookie()
-调用最关键解密签名的cookie->decode_signed_value()
-版本2签名解密->_decode_signed_value_v2()
, 调用顺序就是这样,看下面摘取源码验证的脚步吧!
1 |
|
Tornado设置cookie使用说明(避坑指南)
set_secure_cookie
方法中的参数:expires_days
和expires
是定义cookie在浏览器端的过期时间get_secure_cookie
方法中的参数:max_age_days
是定义最大有效天数,tornado在设置cookie时,在cookie信息中保存了一下冗余信息,其中就有创建时间|10:1535385317|
,通过get_secure_cookie
获取时会比对这个时间和当前时间的差值,而源码中max_age_days
默认是31天- cookie是否有效取决于这两个参数中较小的一个,由于
max_age_days
默认是31天,所以如果我们只是在set_secure_cookie
中设置expires_days
只能保证浏览器存储次cookie的时长,服务器获取到此cookie解密时会默认以31天比对,此时我们设置的expires_days
就失去了应有的效果 - tornado在设置包含了一些冗余信息,其中就有创建时间,也就是说tornado设置cookie不只是依靠浏览器的过期时间,还在设置cookie的值时自己保存了一个时间戳,以避免一些应浏览器客户端和服务器时间不匹配导致的问题。所以我们在取一个cookie时记得注意
max_age_days
的指定,以防默认 31 天时长坑了自己