flask—flask_session
flask 默认提供的 session 功能还是很简单的,满足了基本的功能。但是我们看到 flask 把 session 的数据都保存在客户端的 cookie 中,这里只有用户名还好,如果有一些私密的数据(比如密码,账户余额等等),就会造成严重的安全问题。所以我们会使用 flask-session 这个三方的库,它把数据保存在服务器端(本地文件、redis、memcached),客户端只拿到一个 sessionid。
安装flask_session
pip install flask_session
使用:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'Wu'
from redis import Redis
from flask import Flask, session
from flask_session import RedisSessionInterface
app = Flask(__name__)
app.secret_key = 'request-se1@3'
conn = Redis(......)
app.session_interface = RedisSessionInterface(conn, key_prefix='se__', use_signer=True, permanent=True)
# key_prefix:设置redis中key的前缀
# use_signer:是否使用签名算法
# permanent:设置是否持久化,如果为False,那么设置的cookie超时时间将无效。cookie将会在关闭浏览器时失效。
@app.route('/login')
def index():
session['username'] = 'test'
return 'index'
if __name__ == '__main__':
app.run()
源码流程:
app.session_interface = RedisSessionInterface(conn, key_prefix='se')
通过RedisSessionInterface实例化对象app.session_interface,重新定义了app.session_interface。下面我们来看一下RedisSessionInterface类的__init__方法。
def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
if redis is None:
from redis import Redis
redis = Redis()
self.redis = redis
self.key_prefix = key_prefix # 设置redis中key的前缀
self.use_signer = use_signer
self.permanent = permanent
下面是flask中的open_session方法。
def open_session(self, request):
return self.session_interface.open_session(self, request)
由于我们重新定义了app.session_interface,所以open_session方法会执行RedisSessionInterface类中的open_session方法。
class RedisSessionInterface(SessionInterface):
serializer = pickle
session_class = RedisSession
def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
if redis is None:
from redis import Redis
redis = Redis()
self.redis = redis
self.key_prefix = key_prefixa
# 设置redis中key的前缀
self.use_signer = use_signer
# 是否使用签名算法
self.permanent = permanent
# 设置是否持久化,如果为False,那么设置的cookie超时时间将无效。cookie将会在关闭浏览器时失效。
以上是RedisSessionInterface类的构造方法,在构造方法中设置了一些初始值。
def open_session(self, app, request):
# 去cookie中获取key为session对应的值
sid = request.cookies.get(app.session_cookie_name)
if not sid:
# 创建一个随机字符串
# sid = 6dc1f9bb-1bdd-4bdf-8e3b-b8b98495466e
sid = self._generate_sid()
# 生成一个特殊的字典(session)并返回 {sid,''}
return self.session_class(sid=sid, permanent=self.permanent)
if self.use_signer:
signer = self._get_signer(app)
if signer is None:
return None
try:
sid_as_bytes = signer.unsign(sid)
sid = sid_as_bytes.decode()
except BadSignature:
sid = self._generate_sid()
return self.session_class(sid=sid, permanent=self.permanent)
if not PY2 and not isinstance(sid, text_type):
sid = sid.decode('utf-8', 'strict')
# 根据前缀和随机字符串,去redis中获取值
# sid = se__6dc1f9bb-1bdd-4bdf-8e3b-b8b98495466e
val = self.redis.get(self.key_prefix + sid)
# 如果能从redis中获取到值。
if val is not None:
try:
# 将redis中存放的值loads成一个字典
data = self.serializer.loads(val)
# 将字典转换成特殊的字典,
return self.session_class(data, sid=sid)
except:
return self.session_class(sid=sid, permanent=self.permanent)
return self.session_class(sid=sid, permanent=self.permanent)
上面就是RedisSessionInterface类中的open_session方法。open_session方法处理完成后由save_session方法,将session序列化后保存到redis中,并设置到cookie中。
def save_session(self, app, session, response):
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
if not session:
if session.modified:
self.redis.delete(self.key_prefix + session.sid)
response.delete_cookie(app.session_cookie_name,
domain=domain, path=path)
return
httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
expires = self.get_expiration_time(app, session)
# 将session中保存的特殊字典,转换成普通字典,再序列化成字符串
val = self.serializer.dumps(dict(session))
# 将序列化后的字符串保存到redis中
"""
{
se__6dc1f9bb-1bdd-4bdf-8e3b-b8b98495466e:{'username':test, sid:6dc1f9bb-1bdd-4bdf-8e3b-b8b98495466e}
}
"""
self.redis.setex(name=self.key_prefix + session.sid, value=val,
time=total_seconds(app.permanent_session_lifetime))
if self.use_signer:
session_id = self._get_signer(app).sign(want_bytes(session.sid))
else:
session_id = session.sid
# session:session_id , session_id就是利用uuid生成的随机字符串
# expires用于设置超时时间。
response.set_cookie(app.session_cookie_name, session_id,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)

浙公网安备 33010602011771号