flask默认提供了session, 但是存在以下问题:

  ① session数据存在客户端, 不安全

  ② 大小有限制

  ③ 增加了客户端的压力

所以才产生了很多第三方的session机制, 我使用的是flask_session, 也是官方认可的一个.

安装flask_session

如何使用flask_session

导入flask_session

from flask_session import Session

重新封装flask的session机制

实例化一个Session对象, 将flask实例传进去

app = Flask(__name__)
app.config["SESSION_TYPE"] = 'redis' # 如何存放session
app.config["SESSION_REDIS"] = redis.Redis(host="192.168.233.128", port=6379) # 连接redis的配置
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=1) #session的有效期
Session(app)

flask默认的session是存放在浏览器中的, 这个使用flask_session, 我准备将session存放在redis中, 所以需要做这些配置

下面看看Session实例化时都做了些什么

Session对app做了些什么?

class Session(object):
def __init__(self, app=None):
self.app = app
if app is not None:
self.init_app(app)

形参app就是传进来的app实例, 所有就会执行self.init_app(app), 看看有做了什么?

    def init_app(self, app):
app.session_interface = self._get_interface(app)

这个函数很无聊, 就调用了一个self._get_interface(app), 其实session_interface就是flask所需要的一个操作session的接口, 在这里重新提供了一个接口, 当在进行session存取时候, 就会使用这个新的存取方式

    def _get_interface(self, app):
config = app.config.copy() # 将flask实例的配置config拷贝了一份
# 设置这些值, 如果已经存在就不会再设置了
config.setdefault('SESSION_TYPE', 'null') # session存储的类型
config.setdefault('SESSION_PERMANENT', True)
config.setdefault('SESSION_USE_SIGNER', False)
config.setdefault('SESSION_KEY_PREFIX', 'session:') # 存在数据中的key中前缀, 最后就会看到, 类似于session: uuid4
config.setdefault('SESSION_REDIS', None) # redis连接
config.setdefault('SESSION_MEMCACHED', None)
config.setdefault('SESSION_FILE_DIR',
os.path.join(os.getcwd(), 'flask_session'))
config.setdefault('SESSION_FILE_THRESHOLD', 500)
config.setdefault('SESSION_FILE_MODE', 384)
config.setdefault('SESSION_MONGODB', None)
config.setdefault('SESSION_MONGODB_DB', 'flask_session')
config.setdefault('SESSION_MONGODB_COLLECT', 'sessions')
config.setdefault('SESSION_SQLALCHEMY', None)
config.setdefault('SESSION_SQLALCHEMY_TABLE', 'sessions')
# 下面都是根据不从的session存储类型, 去获取不同的连接对象, 这个对象就可以存取session
if config['SESSION_TYPE'] == 'redis':
session_interface = RedisSessionInterface(
config['SESSION_REDIS'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'memcached':
session_interface = MemcachedSessionInterface(
config['SESSION_MEMCACHED'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'filesystem':
session_interface = FileSystemSessionInterface(
config['SESSION_FILE_DIR'], config['SESSION_FILE_THRESHOLD'],
config['SESSION_FILE_MODE'], config['SESSION_KEY_PREFIX'],
config['SESSION_USE_SIGNER'], config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'mongodb':
session_interface = MongoDBSessionInterface(
config['SESSION_MONGODB'], config['SESSION_MONGODB_DB'],
config['SESSION_MONGODB_COLLECT'],
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
config['SESSION_PERMANENT'])
elif config['SESSION_TYPE'] == 'sqlalchemy':
session_interface = SqlAlchemySessionInterface(
app, config['SESSION_SQLALCHEMY'],
config['SESSION_SQLALCHEMY_TABLE'],
config['SESSION_KEY_PREFIX'], config['SESSION_USE_SIGNER'],
config['SESSION_PERMANENT'])
else:
session_interface = NullSessionInterface() return session_interface # 返回可能操作数据库中的session的对象

看看能够操作session的对象长什么样子.

    def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
if redis is None:
from redis import Redis
redis = Redis()
self.redis = redis # 我配置的redis连接对象, 他就靠这个去连接数据库的
self.key_prefix = key_prefix # 定义的session key的前缀
self.use_signer = use_signer
self.permanent = permanent

上面说了, flask操作session的session_interface变成了新的, 这个session_interface中肯定有存取session的方法, 到底是怎么存取的, follow me.

存放session, key就是 前缀:uuid4

    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) # 1. 先进行删除
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)
val = self.serializer.dumps(dict(session))
self.redis.setex(name=self.key_prefix + session.sid, value=val, # 2. 在进行设置
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
response.set_cookie(app.session_cookie_name, session_id,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)

获取session, 根据用于请求时携带的session, 获取Redis种的数据

    def open_session(self, app, request):
sid = request.cookies.get(app.session_cookie_name) # 1.从cookie中获取存放在浏览器的session
if not sid:
sid = self._generate_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')
val = self.redis.get(self.key_prefix + sid) # 2. 从redis中获取 前缀 + session 的值, 这个值就是你使用session["user"] = user, 存的值
if val is not None: # 3. 判断获取结果
try:
data = self.serializer.loads(val) # 4. 取获取到的结果进行反序列化, 得到session中的数据
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)

到此为止就是flask_session的工作流程

flask_session的应用

下面是我做的一个完成的应用

from flask import Flask, session, request, render_template, redirect
from flask import views
from flask_session import Session
import redis
from datetime import timedelta # 当时使用了Session, 小写的flask原生的session依然需要导入, 因为设置session还是通过这个, 只不过存储session的方式改变了 app = Flask(__name__)
app.config["SESSION_TYPE"] = 'redis' # 指定session存储的类型
app.config["SESSION_REDIS"] = redis.Redis(host="192.168.233.128", port=6379) # 创建redis连接
app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=1) # 执行session的有效时间
Session(app) # 使用Session对session的存储机制重新定义 @app.before_request
def confirm():
"""
校验用户是否已经登录
:return:
"""
if session.get("user") or request.path == "/login":
return None
else:
return redirect('/login') class LoginView(views.MethodView):
def get(self):
return render_template("login.html") def post(self):
u = request.form.get("username")
p = request.form.get("password")
if p == "wang": # 当用户登陆成功后, 在session中设置一个标识, 标识用户已经登录了
session["user"] = u
return "登录成功"
else:
return "error" @app.route('/index', endpoint="index")
def index():
return "index" app.add_url_rule("/login", view_func=LoginView.as_view("login")) if __name__ == '__main__':
app.run(host="192.168.12.29", port=80, debug=True)

最新文章

  1. C++内存对齐总结
  2. HDU 4832 Chess (DP)
  3. Xamarin安装和跳坑指南
  4. 今天说一下where 中 exists 和 in 里面的一些区别
  5. [Asp.net]SignalR实现实时日志监控
  6. centos7.0 安装vsftp实录
  7. 基本语法 protocols Category extension
  8. mysql完整备份时过滤掉某些库
  9. How to solve the SVDI SN Number Display Problem
  10. 清理vs工程文件(python2.7)
  11. CentOS6.4安装ati显卡驱动
  12. [转]Android NDK几点回调方式
  13. Log4Net配置 转
  14. 枚举进行位运算 枚举组合z
  15. mysql 闪回原理
  16. WINDOWS消息和窗口简介
  17. The Unique MST POJ - 1679 最小生成树判重
  18. SHELL有用的命令
  19. Ubuntu下设置环境变量
  20. 如何在HPUX的终端提示符前显示当前登录用户信息和所在目录

热门文章

  1. Django后台注册
  2. javax.swing.JComponent 调用顺序
  3. C# 程序启动最小化至任务栏及闪烁
  4. July 01st 2017 Week 26th Saturday
  5. easyui学习笔记9—手风琴格子的增,删和选择
  6. [EffectiveC++]item35:考虑virtual函数以外的其他选择
  7. 20140322 卡迪夫城VS利物浦,拔出重剑,有惊无险
  8. ORACLE查询删除重复记录
  9. Loj#572. 「LibreOJ Round #11」Misaka Network 与求和
  10. MyBatis(7)高级查询