cookie和session
服务端和客户端之间的联系一般是根据http协议来进行的 但是http协议是无状态的 无状态会有状态的概念大概如下
有状态
- 甲:你吃午饭了吗
- 乙:吃了
- 甲:吃了什么菜
- 乙:吃了鸡蛋
无状态
- 甲:你吃午饭了吗
- 乙:吃了
- 甲:吃了什么菜
- 乙:你说什么时候吃什么菜 早饭?午饭?还是晚饭
因此服务端和客户端之间需要一种机制来记录用户的状态 这种机制在客户端那边是cookies 在服务端那边是session
cookies可以存储在磁盘 内存里面 session可以存储在内存 缓存 redis甚至磁盘中
aiohttp session
flask框架具有内置的session机制 我以前用起来觉得非常方便以至于我觉得这个不重要 aiohttp不具有内置的session机制 但是具有第三方模块支持 aiohttp_session
安装这个第三方模块真的挺费事 因为依赖模块实在太多了 而且aiohttp_session是可以依赖redis作为缓存的 还需要安装redis和一些相关模块 下面的开始的实例我没有使用redis作为存储位置 而是使用了EncryptedCookieStorage 后面附加了使用redis存储session的例子
dependencies
- python3.5.3+
- cryptography
- aioredis
安装模块
- pip3 install cryptography(必要时进行upgrade 可能版本太低)
- pip3 install aiohttp_session[secure]
- pip3 install aiohttp_session[aioredis] (需要安装redis libhiredis-dev hiredis libssl-dev)
- pip3 install aiohttp_session[aiomcache]
pip3 install aiohttp_sessionsss
上面的安装问题真的太多 谷歌好几次才解决
存储位置选择
所有仓库是使用名为AIOHTTP_COOKIE_SESSION的对象来进行存储数据的
可以使用的仓库有
- SimpleCookieStorage 把session数据以明文json字符串的格式存在cookies body中 只用来测试 非常不安全
- EncryptedCookieStorage 存储数据在cookie中的格式跟SimpleCookieStorage一样 但是使用了cryptography的Fernet cipher加密算法进行加密
- RedisStorage 存json化的数据到redis中 格式是name+reids key
- MemcachedStorage 跟RedisStorage类似 但是使用memcache数据库进行存储
使用
使用上跟flask的session大同小异 但是需要在init app阶段将session安装到app上 设定一个32位bytes作为加密密钥 跟flask session的secret key类似
session是一个dict like的对象
设定session1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26from aiohttp import web
import datetime
from aiohttp_session import get_session
async def login(request):
engine = await aio_engine.init_engine()
data = await request.json()
print("data", data)
if "name" not in data or "psw" not in data:
return web.json_response({
"status": False
})
name = data["name"]
psw = data["psw"]
verify = await keeper.verify(engine, name = name, psw = psw)
if verify:
session = await get_session(request)
session["ooad"] = name
session["login"] = psw
session["time"] = str(datetime.datetime.now())
return web.json_response({
"status": True
})
return web.json_response({
"status": False
})
检查是否含有具体session字段值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from aiohttp import web
import datetime
from aiohttp_session import get_session
async def need_cookies_page(request):
engine = await aio_engine.init_engine()
session = await get_session(request)
if "ooad" not in session or "login" not in session or "time" not in session:
return web.json_response({
"status": False
})
name = session["ooad"]
psw = session["login"]
r = await keeper.verify(engine, name = name, psw = psw)
if r:
return web.json_response({
"status": True
})
return web.json_response({
"status": False
})
`
setup app1
setup(app, EncryptedCookieStorage(b'Thirty two length bytes key.'))
效果
login result
login cookies
cookies check
使用redis存储session
这里有个问题 就是aiohttp本事内置一个asyncio event loop执行所有跟app相关的协程了 但是当我们使用redis作为仓库进行存储session的时候需要使用到aioredis进行支持 但是这个也是异步io连接模块 因此我们初始化redis pool的时候也需要一个event loop进行运行这个初始化的协程 一旦这个event loop跟web.run_app混在一起就会报错 event loop is already run
正确的做法是分开 并且在执行redis pool连接的event loop run_until_complete处获取返回值 得到需要的storage
1 | from aiohttp_session import setup, redis_storage |
1 | app = session_redis.setup_session_support(app) |
效果
可以看到生成的cookies值确实存在了redis中
postman中获取的cookies
redis中也存有一样的cookies