Flask - Session

Posted wcx666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask - Session相关的知识,希望对你有一定的参考价值。

Flask-Session

 

1. Flask-Session 源码一瞥

  • Session类实例化
    #在app.py中实例化
    Session(app)
  • 实例化后执行__new__方法,然后执行__init__方法
     def __init__(self, app=None):
            self.app = app
            if app is not None:
                self.init_app(app)
    
        def init_app(self, app):
            """This is used to set up session for your app object.
            :param app: the Flask app object with proper configuration.
            """
            #执行 _get_interface 获取session接口
            app.session_interface = self._get_interface(app)

  • 执行 _get_interface 方法
       def _get_interface(self, app):
            config = app.config.copy()   # 浅拷贝,此时app.config并没有写相关的东西
            config.setdefault(SESSION_TYPE, null)            #设置默认值
            config.setdefault(SESSION_PERMANENT, True)
            config.setdefault(SESSION_USE_SIGNER, False)
            config.setdefault(SESSION_KEY_PREFIX, session:)
            config.setdefault(SESSION_REDIS, None)            #redis好用
            config.setdefault(SESSION_MEMCACHED, None)       #可以忽略以前使用,支持数据类型少,不支持持久化,redis比他好
            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)
    
            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
  • 当未设置app.config["SESSION_TYPE"] 执行  NullSessionInterface()
    class NullSessionInterface(SessionInterface):
        """Used to open a :class:`flask.sessions.NullSession` instance.
        """
        def open_session(self, app, request):
            return None
    
    #所以当未设置config["SESSION_TYPE"],时候 open_session 返回None

    注: 未设置 app.config["SESSION_TYPE"] 时,此时在flask项目中默认生效的还是内置的session,此时仍然需要secret_key配置

  • 若是对 app.config["SESSION_TYPE"] 配置以及对相应的redis进行配置则:在_get_interface 方法中执行相应的内容
    app.config["SESSION_TYPE"] = "redis"
    #在任何情况下都要将redis放到内网,不允许暴露到公网
    app.config["SESSION_REDIS"] = Redis(host="127.0.0.1",port=6379)
    #将cookie name 修改为其他名字
    app.config["SESSION_COOKIE_NAME"] = "HEHE"
    
    Session(app)

    实例化的  RedisSessionInterface 对象 __init__方法

        def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
            if redis is None:
                from redis import Redis
                redis = Redis()# 创建redis连接,此时第一传进来的是一个redis连接
            self.redis = redis
            self.key_prefix = key_prefix
            self.use_signer = use_signer
            self.permanent = permanent
  • 当认证成功够通过open_session 会从session中取到对应值即从cookies中获取值
        def open_session(self, app, request):
            #取出session
            sid = request.cookies.get(app.session_cookie_name)
            if not sid:
                sid = self._generate_sid()
                return self.session_class(sid=sid, permanent=self.permanent)
            if self.use_signer:  #False
                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)   #session:    f95dbedd-783c-4cd3-9cdf-54f11c9790e0
            if val is not None:
                try:
                    #序列化解包
                    data = self.serializer.loads(val)
                    return self.session_class(data, sid=sid) #session_class 将session以字典的形式返回
                except:
                    return self.session_class(sid=sid, permanent=self.permanent)
            return self.session_class(sid=sid, permanent=self.permanent)
  • 通过save_session进行存储
            if login_form_data.validate():
                session["user"] = login_form_data.data.get("username")
                # 此时进过save_session方法,此时以字典的形式存储,通过键值"user"取值
                return str(session["user"])
       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
    
            # Modification case.  There are upsides and downsides to
            # emitting a set-cookie header each request.  The behavior
            # is controlled by the :meth:`should_set_cookie` method
            # which performs a quick check to figure out if the cookie
            # should be set or not.  This is controlled by the
            # SESSION_REFRESH_EACH_REQUEST config flag as well as
            # the permanent flag on the session itself.
            # if not self.should_set_cookie(app, session):
            #    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,
                             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_cookies_name
    #将cookie name 修改为其他名字
    app.config["SESSION_COOKIE_NAME"] = "HEHE"

     

 

以上是关于Flask - Session的主要内容,如果未能解决你的问题,请参考以下文章

flask session

Session处理实例—Flask网站制作(13)

代码在Flask中返回render_template后不起作用

flask 请求处理流程及其源代码分析sessioncookie生成源码

六十一:Flask.Session之flask操作session

Flask组件之Flask-session