HTTP 是一个没有状态的协议,这种特点带来的好处就是执行效率较高,但是缺点也非常明显,这个协议本身是不支持网站关联的,例如http://ceshiren.com/和https://ceshiren.com/t/topic/9737/7这两个网站,必须要使用别的方法将它们两个关联起来。那就是用 session、cookie 和 token。
1)session 即会话,是一种持久网络协议,起到了在用户端和服务器创建关联,从而交换数据包的作用。
2)cookie 是“小型文本文件”,是某些网站为了辨别用户身份,进行 Session 跟踪而储存在用户本地终端上的数据(通常经过加密),由用户的客户端计算机暂时或永久保存的信息。
3)token 在计算机身份认证中是令牌(临时)的意思,在词法 Fenix 中是标记的意思。
1.环境搭建演示
为了避免其他因素的干扰,使用 Flask 编写一个简单的 demo server 程序,用以演示 cookie 与 session。
demo server 的代码如下:
from flask import Flask,session,Request,request,make_response
app = Flask(__name__)
request : Request
app.secret_key = "key"
@app.route('/')
def hello_world():
return 'hello,world!'
@app.route("/session")
def session_handle():
#读取请求
for k, v in request.args.items():
#收到请求后写入session
session[k] = v
#创建服务端响应,将session的内容打印出来
resp = make_request({k: v for k, v in session.items()})
for k,v in request.args.item():
#给服务端设置cookie,并添加cookie字符串进行标识
resp.set_cookie(f"cookie_{k}",v)
return resp
复制代码
2 分析 session、cookie 和 token
(1)session 和 cookie 的区别演示
首先使用浏览器的无痕模式对演示网站发起访问,并传入 a、b 两个参数。以一次请求为例,查看 cookie 的传递过程。
第一次请求的请求头信息如下(可以看到没有任何的 cookie 信息):
GET /session?a=1&b=2 HTTP/1.1
Host : 127 0.0.1:5000
Connection:keep-alive
Pragma: no-cache
Cache-Control: no-cashe
sec-ch-ua:"Not A;Brand";v="99","Chromium";v="90","Google Chrom";v="90"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent:Mozilla/5.0(Macintosh;Intel Mac OS X 10_15_0)AppleWebKit/537.36
(KHTML,like Gecko) Chrome/90.0.4430.212 Safari/573.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/
webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding:gzip,deflate,br
Accept-Language: en
复制代码
第一次请求的响应头信息,向客户端返回了 set-cookie 字段:
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 18
Set-cookie:cookie_a=1;Path=/
Set-cookie:cookie_b=2;Path=/
Vary:cookie
Set-cookie: session-eyJhIjoiMSIsImIiOiIYInO.YKSvNA.2sSLXbraXxQ-MfKOLhoLJPZmV9U;
HttpOnly;Path=/
Server:Werkzeug/1.0.1 Python/3.8.7
Date: Web,19 May 2021 06 24:52 GMT
复制代码
第二次请求的请求头信息,客户端向服务端请发起求时,请求头多出了一个 cookie 信息,并提交了和第二次 set-cookie 相同的信息:=
GET /session?a=1&b=2 HTTP/1.1
Host: 1270.0.1:5000
省略
cookie: cookie_a=1;cookie_b=2; session=eyJhIjoiMSIsImIiOiIyIn0.YKSvNA.
2sSaLXbraXxQ-MfKOLhoLJPZmV9U
复制代码
当用户访问带 cookie 的浏览器时,这个服务端就为这个用户产生了唯一的 cookie,并以此作为索引在服务端的后端数据库产生一个项目,接着就给客户的响应报文 中添加一个叫做 Set-cookie 的首部行,格式为 k:v.
该用户下次再访问此网站,在服务端发起请求时添加一个名为 cookie 首部行,浏览器就可以得知用户的身份,用户就不需要再次输入一些个人信息了。
使用 CURL 对网站发起了一个 GET 请求,并传入 a、b 两个参数
curl 'http://127.0.0.1:5000/session?a=1&b=2' -v -s &>session
复制代码
查看 session 文件内的请求及响应内容,如下所示:
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (1270.0.0.1) port 5000 (#0)
> GET /session?a=1&b=2 HTTP /1.1
> Host:1270.0.1:5000
> User-Agent: curl/7.64.1
> Accept:*/*
>
* HTTP 1.0,assume close after body
< HTTP/1.0 200 OK
< Content-Type:application/json
< Content-Length: 18
< Set-cookie: cookie_a=1; Path=/
< Set-cookie: cookie_b=2; Path=/
< Vary: Cookie
< Set-cookie: session=eyJhIjoiMSIsImIiOiIyIn0.EWX6Qg.M8tEGPyRhlf0iUiLktEqup-4e-U;
HttpOnly; Path=/
< Server: Werkzeug/1.0.1 Python/3.7.5
<
{[18 bytes data]
*Closing connection 0
{"a":"1","b":"2"}}
复制代码
从上面的内容可以发现,响应值多出了 3 个 Set-cookie 字段。其中有一个 Set-cookie 显示为 session=eyJhijoiMSIsIMIiOilyIn0.EWX6Qg.M8tEGPyRhlf0iUiLKtEqup-4e-U;HttpOnly;Path=/,这是 Session 内容的加密串格式,是通过 cookie 方式传递的。
(2)token 演示
GitHub 中有一个使用 token 的非常经典的场景。访问 GitHub 页面,依次点击“settings”->"Developer setting"->"Personal access token"项,就会生成一个用于访问 GitHub API 的 token。这个 token 是没有时效性的,“任何人”都可以使用 token 来代替 HTTPS 的 Git 密码,也可以用 API 进行身份验证。
使用 OAuth 令牌对 GitHub API 进行身份验证(因返回的结果中个人信息太多所以省略展示)。
$ curl -u username:$token https://api.GitHub网站/user
复制代码
token 是无状态的,客户端传递用户数据给服务端,服务端将数据加密就生成了 token 并传回给客户端。这样客户端每次访问 GitHub 时都传递 token,而服务端解密 token 之后,即可了解客户的信息。如图 6-26 所示。
在 GitHub 中,token 只会生成一次,且不会过期,不过在很多其他的 Web 网站中,token 会过期。
3.session、cookie 和 token 的联系
session 和 cookie 之间的联系如图 6-27(a)所示,token 身份验证流程如啼眼 6-27(b)所示。
(1)session 存储在服务端,cookie 存储在客户端
(2)cookie 可设置为长时间保持;session 一般失效时间较短,客户端关闭(默认情况下)或者 session 超时都会失效。
(3)session 记录会话信息;token 不会记录会话信息,token 是无状态的。
搜索微信公众号:TestingStudio 霍格沃兹的干货都很硬核
评论