诚意
诚意如你,当一诚的态度对待

导航

 

 

 

一:简介

flask-session是flask框架的session组件,由于原来flask内置session使用签名cookie保存,如果我们在session中不存敏感信息还好,如果存的是敏感信息那么信息安全是没有保障的,该flask_session组件则将支持session保存到多个地方,如:

  • redis
  • memcached
  • filesystem
  • mongodb
  • sqlalchmey

 

二:案例

1:安装

pip3 install Flask-Session

 

2:配置session存储到redis中

服务端

from flask import Flask,session
from flask_session import Session
from redis import Redis

app = Flask(__name__)


app.config['SESSION_TYPE'] = 'redis'  # session类型为redis
app.config['SESSION_PERMANENT'] = False  # 如果设置为True,则关闭浏览器session就失效。
app.config['SESSION_USE_SIGNER'] = False  # 是否对发送到浏览器上session的cookie值进行加密
app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前缀
app.config['SESSION_REDIS'] = Redis(host='127.0.0.1',port=6379,db=6)  # 用于连接redis的配置

Session(app)


@app.route('/')
def index():
    session['user'] = 'hi'
    return 'hello'

if __name__ == '__main__':
    app.run(debug=True)

 

 

3:浏览器访问服务端查看是否有session

 

 

4:查看redis缓存中是否有redis

 

三:源码解析

请先查看 上下文源码 

 

1:设置 session_interface

class Session(object):

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

    def _get_interface(self, app):
        config = app.config.copy()   #浅拷贝
        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)
        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')

        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

 

class RedisSessionInterface(SessionInterface):
  def __init__(self, redis, key_prefix, use_signer=False, permanent=True):
        if redis is None:
            from redis import Redis
            redis = Redis()
        self.redis = redis
        self.key_prefix = key_prefix
        self.use_signer = use_signer
        self.permanent = permanent

 

    def __init__(self, host='localhost', port=6379,
                 db=0, password=None, socket_timeout=None,
                 socket_connect_timeout=None,
                 socket_keepalive=None, socket_keepalive_options=None,
                 connection_pool=None, unix_socket_path=None,
                 encoding='utf-8', encoding_errors='strict',
                 charset=None, errors=None,
                 decode_responses=False, retry_on_timeout=False,
                 ssl=False, ssl_keyfile=None, ssl_certfile=None,
                 ssl_cert_reqs='required', ssl_ca_certs=None,
                 max_connections=None):
  。。。。。。。。

 

 

 

 

 

 2:执行上下文时获取到session并存入到redis中

def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                ctx.push()

 

 

def push(self):
            if self.session is None:
            session_interface = self.app.session_interface   #这里的session_interface是被浅拷贝了,所以上面得到的session_interface和这里的是一个空间
            self.session = session_interface.open_session(  #这里的session_interface中的open_session()就执行的是下面的
                self.app, self.request
            )

            if self.session is None:
                self.session = session_interface.make_null_session(self.app)

 

 拿到cookie中的session

class RedisSessionInterface(SessionInterface):
   def open_session(self, app, request):
        sid = request.cookies.get(app.session_cookie_name)   #这个是app.config源码中的那个session_cookie_name   ,里面是session
        if not sid:  #从cookie中获取的session id 
            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)   #session:6a899d9e-c5ac-49a6-b43e-f5fb0044bb2e
if val is not None:
            try:
                data = self.serializer.loads(val) #{key:value}
                return self.session_class(data, sid=sid)       #获取的session替换原来放session的那个偏函数
except:
                return self.session_class(sid=sid, permanent=self.permanent)
        return self.session_class(sid=sid, permanent=self.permanent)

 

把session中存放在redis中  
def save_session(self, app, session, response): domain = self.get_cookie_domain(app) path = self.get_cookie_path(app)
    。。。。。。。
       self.redis.setex(name=self.key_prefix + session.sid, value=val,
time=total_seconds(app.permanent_session_lifetime))
     。。。。。。。

 

posted on 2019-01-14 14:52  诚意  阅读(517)  评论(0)    收藏  举报