Flask-Session使用Redis
一、介绍
- 在Flask中,session数据默认是以加密的cookie形式存储在用户的浏览器中的。
- 但是,真正的session数据应该存储在服务器端。
- Django框架会将session数据存储在数据库的
djangosession
表中,而Flask则可以通过第三方库如flask-session
来实现,通常将session存储在Redis这样的内存数据库中。 - 此外,Flask也可以使用JWT(JSON Web Tokens)来处理session。
二、使用
1. 安装
-
要使用Flask的session功能,首先需要安装
flask-session
库:pythonpip install flask-session
2.方式一
-
创建Redis连接,并使用
RedisSessionInterface
来将session数据存储到Redis中。 -
通过
session
字典来存储和获取数据。 -
示例
-
python
from flask import Flask, session from flask_session.redis import RedisSessionInterface from redis import Redis app = Flask(__name__) # 创建一个 Flask 应用对象 app.debug = True # 设置调试模式为开启 app.config['SESSION_COOKIE_NAME'] = 'hello_session' # 设置会话 cookie 名称,前端显示 conn_redis = Redis(host="localhost", port=6379) # 创建一个 Redis 连接对象,连接本地 Redis 服务器 # 设置应用的会话接口为基于 Redis 的会话 # app :Flask 应用对象 # client :Redis 客户端对象 # key_prefix :用于在数据库中存储会话的键名前缀 app.session_interface = RedisSessionInterface(app, client=conn_redis, key_prefix='bruce') @app.route('/') def index(): # 定义路由处理函数 session['serret'] = '123456' # 设置会话变量 'serret' return 'index' # 返回字符串 'index' if __name__ == '__main__': app.run()
-
3.方式二
-
设置session的cookie名称和配置,指定session类型为redis。
-
创建Redis连接对象,并使用
Session
类来初始化Flask应用。 -
示例
-
python
from flask import Flask, session from flask_session import Session from redis import Redis app = Flask(__name__) app.session_cookie_name = 'hello_session' # 配置会话类型为redis,并指定redis的主机和端口 app.config['SESSION_TYPE'] = 'redis' app.config['SESSION_REDIS'] = Redis(host='127.0.0.1', port=6379) # 将会话配置应用到Flask应用程序中 Session(app) @app.route('/') def index(): session['secret'] = '123456' return 'index' if __name__ == '__main__': app.run()
-
4.相关配置
python# 设置会话的cookie名称 app.session_cookie_name = 'hello_session' # 配置会话类型为redis app.config['SESSION_TYPE'] = 'redis' # Redis配置 app.config['SESSION_REDIS'] = Redis(host='127.0.0.1', port=6379) # Redis服务器的密码(如果有) app.config['SESSION_REDIS_PASSWORD'] = 'password' # Redis数据库索引 app.config['SESSION_REDIS_DB'] = 0 # 会话的过期时间,默认是31天 app.config['PERMANENT_SESSION_LIFETIME'] = 3600 * 24 * 31 # 是否对发送到浏览器端的cookie进行签名 app.config['SESSION_USE_SIGNER'] = True # 是否需要HTTPS传输cookie app.config['SESSION_COOKIE_SECURE'] = False # 设置cookie的httponly属性,防止客户端脚本访问cookie app.config['SESSION_COOKIE_HTTPONLY'] = True # 设置cookie的SameSite属性,防止CSRF攻击 app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
三、源码解析
-
使用Redis时,使用的是RedisSessionInterface
-
RedisSessionInterface继承ServerSideSessionInterface
-
open_session
-
python
def open_session(self, app, request): # 从cookie中获取会话ID sid = request.cookies.get(app.config["SESSION_COOKIE_NAME"]) # 如果没有会话ID,生成一个新的,并返回 if not sid: sid = self._generate_sid(self.sid_length) return self.session_class(sid=sid, permanent=self.permanent) # 如果会话ID已经签名,解除签名 if self.use_signer: try: sid = self._unsign(app, sid) except BadSignature: sid = self._generate_sid(self.sid_length) return self.session_class(sid=sid, permanent=self.permanent) # 从数据库中检索会话数据 store_id = self._get_store_id(sid) saved_session_data = self._retrieve_session_data(store_id) # 如果已保存会话存在,从文档中加载会话数据 if saved_session_data is not None: return self.session_class(saved_session_data, sid=sid) # 如果已保存会话不存在,创建一个新会话 sid = self._generate_sid(self.sid_length) return self.session_class(sid=sid, permanent=self.permanent)
-
-
save_session
-
python
def save_session(self, app, session, response): domain = self.get_cookie_domain(app) # 获取cookie的域 path = self.get_cookie_path(app) # 获取cookie的路径 name = self.get_cookie_name(app) # 获取cookie的名称 store_id = self._get_store_id(session.sid) # 获取存储ID if session.accessed: # 如果会话已访问 response.vary.add("Cookie") # 响应头中添加Vary信息 if not session: # 如果会话不存在 if session.modified: # 如果会话已修改 self._delete_session(store_id) # 删除会话 response.delete_cookie(key=name, domain=domain, path=path) # 从响应中删除cookie response.vary.add("Cookie") # 响应头中添加Vary信息 return # 返回 if not self.should_set_storage(app, session): # 如果不应该设置存储 return # 返回 self._upsert_session(app.permanent_session_lifetime, session, store_id) # 更新或插入会话 if not self.should_set_cookie(app, session): # 如果不应该设置cookie return # 返回 # 获取额外的所需cookie设置 value = self._sign(app, session.sid) if self.use_signer else session.sid # 获取cookie的值 expires = self.get_expiration_time(app, session) # 获取cookie的过期时间 httponly = self.get_cookie_httponly(app) # 获取cookie的httponly设置 secure = self.get_cookie_secure(app) # 获取cookie的安全设置 samesite = ( self.get_cookie_samesite(app) if self.has_same_site_capability else None ) # 获取相同站点设置(如果支持) response.set_cookie( key=name, value=value, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure, samesite=samesite, ) # 在响应中设置cookie response.vary.add("Cookie") # 响应头中添加Vary信息
-