zoukankan      html  css  js  c++  java
  • Flask第三方组件之flask_session

    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)
  • 相关阅读:
    idea中maven自动导入出现问题
    DDIA
    DDIA
    DDIA
    DDIA
    DDIA
    DDIA
    DDIA
    MIT 6.824 第五次作业Primary-Backup Replication
    MIT 6.824 第四次作业GFS
  • 原文地址:https://www.cnblogs.com/594504110python/p/10139801.html
Copyright © 2011-2022 走看看