將Session 資料存入資料庫 — 使用 Flask-Session套件
《Flask Web 開發實戰》第四次活動開始介紹如何製作部落格,首先第一步是介紹如何製作會員管理的登入、註冊和驗證等功能,使用 Flask-login 套件來執行相關功能。其中 Flask-login 預設是將 user id 存入 session,而 Flask 預設是將 session 資料加密後存入 cookie 中 (關於 cookie 和 session 之間的關係請參考第二次活動內容)。實務上,如網站有多個子系統 (可能有不同的 domain)需要共用使用者資料時,存在 cookie 裡便不符合使用需求。因此有人提出將 session 存入資料庫(如 Redis) ,再根據需要存取。
此篇文章重點將著重於實作 Flask Session Interface
,資料庫採用活動之前介紹過的 SQLite 以及 Flask-Sqlalchemy 套件。
預備動作
本文將使用《Flask Web 開發實戰》第四次活動的程式碼來實作將 cookie 存入資料庫功能。請由下列指令從 github去得最新程式碼,並切換到 tag 8j
。
$ git clone https://github.com/win911/flask_class.git
$ git checkout 8j
所需的 package 列在 requirements.txt
,使用下述指令安裝,前面括弧(venv)
為虛擬環境設定。
(venv)$ pip install -r requirements.txt
本範例需要用到 Flask-Login 套件沒有寫在上述 requirements.txt
,如果沒有請以下述指令安裝安裝。
(venv)$ pip install flask-login
如果是曾經做過之前活動程式碼,更新到此 tag 程式碼資料庫欄位有變動,或者是全新下載的程式碼 (資料庫尚未建立),都是以下列指令更新資料庫:
(venv)$ python manage.py db upgrade
關於SQLAlchemy 資料庫版本控制,參考《Flask Web 開發實戰》第三次活動 Database Migration 投影片。
開發
要實作 Flask Session Interface
,根據Flask Session Interface 文件,需要實作 open_session()
以及 close_session()
方法。除了自行實作這些方法,也可以使用 Flask-Session 套件。首先安裝套件:
(venv) $ pip install flask-session
要使用套件需要修改 config.py
加入 Flask-Session 設定,由於活動中使用 Flask-SQLAlchemy 套件,因此設定裡加上 SESSION_TYPE
設定。
SESSION_TYPE = 'sqlalchemy'
在 app/__init__.py
裡,加上 session
起始設定。
# 一開始 import 相關套件
from flask import Flask, session
from flask_session import Session# 在 create_app(config_name) 方法裡加上下列兩行session = Session(app)
session.app.session_interface.db.create_all()
完整修改請見此 GitHub commit。
完成上述修改後,開啟站台,網站登入和註冊等頁面會一切如常進行。
使用套件後的 Cookie 與 Session 的變化
Flask-Login 將 user id 等資訊儲存在 session 裡,再將 session 加密後儲存在 cookie 裡。如果 Session Protection 設為 strong
,session 儲存的資訊還會再加上 IP address 與 user-agent 等可以更明確定義 request 來源的資料,當發現新 request 裡的這些資料與 session 裡儲存的不一致或 session 過期時,cookie 就會被刪除,使用者就必須重新登入。
Flask-Session 一樣將 user id 等資訊儲存在 session 裡,但改將 session 儲存在資料庫中,cookie 裡儲存的只是 session id (所以會發現 cookie 長度變短)。透過 session id,就可到資料庫中取得對應的 session 資料。
$ sqlite3 data-dev.sqlite
查看SQLite 資料庫裡面有哪些資料表,可以發現多了 sessions 資料表。
sqlite> .tables
alembic_version roles sessions users
查看 sessions table 資訊,其中包括 session_id,資料 data 則為 BLOB 型別:
sqlite> .schema sessions
CREATE TABLE sessions (
id INTEGER NOT NULL,
session_id VARCHAR(255),
data BLOB,
expiry DATETIME,
PRIMARY KEY (id),
UNIQUE (session_id)
);
利用 SQL command 可以取得 session id相對應 data:
sqlite> SELECT quote(data) FROM sessions WHERE session_id='session:6b9750f1-21dd-4503-9a2b-f81e17863178';
X'80037D710028580A0000005F7065726D616E656E7471018858060000005F6672657368710289580A000000637372665F746F6B656E71035828000000666365393466643338326232353737343830633335643935333839313965386163346431366236327104752E'
Session id 帶有預設 prefix 為session:
,可以透過 SESSION_KEY_PREFIX
參數設定。
在 Flask-Session 裡,session 資料透過 pickle 進行序列化後儲存在 sessions 資料表的 data 欄位。
如果想要修改 Session 資料表名稱,可透過 SESSION_SQLALCHEMY_TABLE
參數進行設定,其他可修改變數參考 Flask-Session 官方文件。
小結
除了使用 Flask-Session 套件,也可以自行實作相關方法達成將此 session 存入資料庫的目的。在 Flask Snippets 的 Session 分類裡有其他使用者提供的數種 Flask Session Interface
方式可參考,下次電子報將繼續探索自行實作 Flask Session Interface
的方法。
參考資料
- PyLadies Taiwan: Facebook 粉絲頁、Meetup
- Flask 官方文件: Session Interface
- Flask-login 官方文件
- Flask-Session 官方文件
- Flask Web 開發實戰 — 02 Survey the interaction between cookie and session
- Flask Web 開發實戰 — 04: 投影片
- Flask Server-side session:flask 中的 cookie 和 session 、【Flask源码解读】session 的实现与扩展