簡單說明:
flask_session可以這么說吧,flask原本的session是保存在瀏覽器cookie中的,這樣就產生了一個很重要的問題,如果我們在session中不存敏感信息還好,如果存的是敏感信息那么信息安全是沒有保障的,而flask_session可以讓我們把session的值存儲在redis/Memcached中。
將數據存儲在redis/memcached中然后把所對應的key存放在用戶的cookie中。
實現方式:
在flask源碼中

def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) ctx.push() error = None try: try: response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
ctx.push()方法中有
self.session = self.app.open_session(self.request) if self.session is None: self.session = self.app.make_null_session()
執行的是self.session_interface.open_session(self, request)、
這里的session_interface是flask中默認的,所以我們如果把默認的session_interface重新賦值那么open_session執行的就不會是flask中默認的session_interface而應該是我們重新賦值的類中的open_session
RedisSessionInterface源碼解析:
def open_session(self, app, request): # 從cookie中拿sid 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: 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) if val is not None: try: data = self.serializer.loads(val) 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)
可以看到大致是這么做的,
1.先從cookie中拿值,
2.判斷是否cookie中sid是否存在
3.1如果不存在那么就返回一個特殊的字典
3.2如果有sid那么去redis中拿值,並用pickle反序列化,返回一個字典
當我們在視圖函數中進行session操作的時候會調用save_session看看我們接着來看看save_session做了什么事:
1 def save_session(self, app, session, response): 2 domain = self.get_cookie_domain(app) 3 path = self.get_cookie_path(app) 4 5 # Delete case. If there is no session we bail early. 6 # If the session was modified to be empty we remove the 7 # whole cookie. 8 if not session: 9 if session.modified: 10 response.delete_cookie(app.session_cookie_name, 11 domain=domain, path=path) 12 return 13 14 # Modification case. There are upsides and downsides to 15 # emitting a set-cookie header each request. The behavior 16 # is controlled by the :meth:`should_set_cookie` method 17 # which performs a quick check to figure out if the cookie 18 # should be set or not. This is controlled by the 19 # SESSION_REFRESH_EACH_REQUEST config flag as well as 20 # the permanent flag on the session itself. 21 if not self.should_set_cookie(app, session): 22 return 23 24 httponly = self.get_cookie_httponly(app) 25 secure = self.get_cookie_secure(app) 26 expires = self.get_expiration_time(app, session) 27 val = self.get_signing_serializer(app).dumps(dict(session)) 28 response.set_cookie(app.session_cookie_name, val, 29 expires=expires, httponly=httponly, 30 domain=domain, path=path, secure=secure)
拿到域名,和路徑如果有路徑判斷是否有修改,此處會出現一個bug就是你在修改數據的時候,程序只會檢測到你的第一級數據有沒有變化,而不會檢測到內部的字典是否發生了變化。
這時我們可以在views中self.session['modified'] = True
但是我們更加推薦另一種方式在配置文件中設置
SESSION_REFRESH_EACH_REQUEST = True
這樣有一個好處每次都可以設置session而且可以刷新session的過期時間,在原生的session_interface中還要設置
session.permanent = True
而在我們設置的flask_session中就不用設置了默認為True