zoukankan      html  css  js  c++  java
  • Flask

    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"
  • 相关阅读:
    TFS 2010安装指南
    让C#事件也可以异步触发
    Automated BuildDeployTest using TFS 2010
    BLEND + SKETCHFLOW PREVIEW FOR VISUAL STUDIO 2012
    The trust relationship between this workstation and the primary domain failed
    微软发布官方TFS 2010 Scrum 模板
    Visual Studio 2012 New Features: Compatibility (aka Project RoundTripping)
    Hibernate 的<generator class="native"></generator>的不同属性含义
    WDS桥接和WDS中继的区别
    Upgrading TFS 2010 to TFS 2012 RC,tfs2010升级2012
  • 原文地址:https://www.cnblogs.com/wcx666/p/10447095.html
Copyright © 2011-2022 走看看