flask中的session介紹
在Flask中,session是一個(gè)用于存儲(chǔ)特定用戶會(huì)話數(shù)據(jù)的字典對(duì)象。它在不同請(qǐng)求之間保存數(shù)據(jù)。它通過在客戶端設(shè)置一個(gè)簽名的cookie,將所有的會(huì)話數(shù)據(jù)存儲(chǔ)在客戶端。以下是如何在Flask應(yīng)用中使用session的基本步驟:
首先,你需要設(shè)置一個(gè)秘鑰,這是為了加密你的session數(shù)據(jù):
from flask import Flask, session
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
然后,你可以像操作字典一樣操作session對(duì)象。以下是一個(gè)登錄的例子:
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
#from flask import escape
# 假設(shè) session['username'] 是 "<script>alert('hacked!');</script>"
#safe_username = escape(session['username'])
# safe_username 現(xiàn)在是 "<script>alert('hacked!');</script>"
# escape(session['username'])是在做HTML轉(zhuǎn)義
@app.route('/')
def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if valid_login(username, password):
session['username'] = request.form['username']
return redirect(url_for('index'))
else:
error = 'Invalid username or password'
return render_template('login.html', error=error)
@app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
Flask的session實(shí)現(xiàn)涉及到幾個(gè)關(guān)鍵的組件:session
對(duì)象、session_interface
對(duì)象以及secure_cookie
模塊。以下是這些組件是如何工作以實(shí)現(xiàn)Flask的session的:
-
Session對(duì)象:在Flask中,session被表示為一個(gè)名為
session
的字典對(duì)象。它是LocalProxy
的實(shí)例,LocalProxy
是一種可以動(dòng)態(tài)引用當(dāng)前運(yùn)行環(huán)境(比如請(qǐng)求或應(yīng)用上下文)的特定對(duì)象的代理類。當(dāng)你嘗試訪問session
對(duì)象的屬性或方法時(shí),LocalProxy
會(huì)將這些操作轉(zhuǎn)發(fā)到實(shí)際的會(huì)話對(duì)象,這個(gè)實(shí)際的會(huì)話對(duì)象由session_interface
創(chuàng)建。 -
SessionInterface對(duì)象:
SessionInterface
是一個(gè)抽象基類,定義了用于處理session的接口。Flask自帶的SecureCookieSessionInterface
實(shí)現(xiàn)了這個(gè)接口,使用安全的簽名cookie來存儲(chǔ)session數(shù)據(jù)。當(dāng)一個(gè)請(qǐng)求開始時(shí),SecureCookieSessionInterface
會(huì)從請(qǐng)求的cookies中提取出session數(shù)據(jù),并創(chuàng)建一個(gè)新的SecureCookieSession
對(duì)象。當(dāng)請(qǐng)求結(jié)束時(shí),如果SecureCookieSession
對(duì)象被修改,SecureCookieSessionInterface
會(huì)把它序列化并簽名,然后存回到客戶端的cookies中。【文末附源碼解釋】 -
SecureCookie模塊:這個(gè)模塊實(shí)現(xiàn)了
SecureCookieSession
類,SecureCookieSession
是一個(gè)用于存儲(chǔ)實(shí)際session數(shù)據(jù)的字典子類,它的工作方式和普通的字典一樣。
整體來看,F(xiàn)lask的session實(shí)現(xiàn)工作流程是這樣的:
- 當(dāng)一個(gè)請(qǐng)求開始時(shí),F(xiàn)lask會(huì)創(chuàng)建一個(gè)新的請(qǐng)求上下文,并通過
SecureCookieSessionInterface
從請(qǐng)求的cookies中提取出session數(shù)據(jù),然后創(chuàng)建一個(gè)新的SecureCookieSession
對(duì)象。 - 當(dāng)你在你的視圖函數(shù)中操作
session
對(duì)象(比如設(shè)置session['username'] = 'John'
)時(shí),實(shí)際上你是在操作這個(gè)SecureCookieSession
對(duì)象。 - 當(dāng)請(qǐng)求結(jié)束時(shí),F(xiàn)lask會(huì)檢查
SecureCookieSession
對(duì)象是否被修改。如果被修改,F(xiàn)lask會(huì)通過SecureCookieSessionInterface
和SecureCookie
將SecureCookieSession
對(duì)象序列化并簽名,然后把它存回到響應(yīng)的cookies中。 - 當(dāng)下一個(gè)請(qǐng)求來到時(shí),這個(gè)過程會(huì)再次重復(fù)。
通常流程總結(jié)
- 當(dāng)一個(gè)新用戶(沒有任何session數(shù)據(jù)的用戶)首次訪問你的Flask應(yīng)用時(shí),他們的請(qǐng)求中不會(huì)包含任何session數(shù)據(jù)。在這種情況下,F(xiàn)lask會(huì)為這個(gè)用戶創(chuàng)建一個(gè)新的、空的session對(duì)象。這個(gè)新的session對(duì)象在初始狀態(tài)下是空的,也就是說,它不包含任何數(shù)據(jù)。
- 如果在處理這個(gè)請(qǐng)求的過程中,你的代碼修改了session對(duì)象(例如,通過設(shè)置
session['username'] = 'John'
),那么當(dāng)請(qǐng)求結(jié)束時(shí),F(xiàn)lask會(huì)把這個(gè)session對(duì)象序列化并簽名,然后存入一個(gè)新的Cookie中。這個(gè)新的Cookie會(huì)被發(fā)送到客戶端,一起與響應(yīng)一起傳送。 - 當(dāng)這個(gè)用戶下次訪問你的Flask應(yīng)用時(shí),他們的請(qǐng)求將會(huì)攜帶這個(gè)包含了session數(shù)據(jù)的Cookie。Flask會(huì)在接收到這個(gè)請(qǐng)求時(shí),從Cookie中提取出session數(shù)據(jù),并創(chuàng)建一個(gè)新的session對(duì)象。這樣,你的代碼就可以繼續(xù)訪問和修改這個(gè)session對(duì)象了。
需要注意的是,如果一個(gè)請(qǐng)求沒有修改session對(duì)象,那么Flask就不會(huì)在響應(yīng)中設(shè)置新的Cookie。這是因?yàn)?,沒有必要把一個(gè)沒有變化的session數(shù)據(jù)再次發(fā)送到客戶端。
因此,即使一個(gè)新用戶的首次請(qǐng)求中沒有包含任何session數(shù)據(jù),F(xiàn)lask也能正確地處理文章來源:http://www.zghlxwxcb.cn/news/detail-611899.html
SecureCookieSessionInterface
class SecureCookieSessionInterface(SessionInterface):
"""The default session interface that stores sessions in signed cookies
through the :mod:`itsdangerous` module.
"""
#: the salt that should be applied on top of the secret key for the
#: signing of cookie based sessions.
salt = "cookie-session"
#: the hash function to use for the signature. The default is sha1
digest_method = staticmethod(hashlib.sha1)
#: the name of the itsdangerous supported key derivation. The default
#: is hmac.
key_derivation = "hmac"
#: A python serializer for the payload. The default is a compact
#: JSON derived serializer with support for some extra Python types
#: such as datetime objects or tuples.
serializer = session_json_serializer
session_class = SecureCookieSession
def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None:
if not app.secret_key:
return None
signer_kwargs = dict(
key_derivation=self.key_derivation, digest_method=self.digest_method
)
return URLSafeTimedSerializer(
app.secret_key,
salt=self.salt,
serializer=self.serializer,
signer_kwargs=signer_kwargs,
)
def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None:
s = self.get_signing_serializer(app)
if s is None:
return None
val = request.cookies.get(self.get_cookie_name(app))
if not val:
return self.session_class()
# 獲取session的最大有效期,單位為秒。
max_age = int(app.permanent_session_lifetime.total_seconds())
try:
# 嘗試使用序列化器s的loads方法,對(duì)session cookie的值val進(jìn)行反序列化和簽名驗(yàn)證。如果反序列化和驗(yàn)證成功,就用這些數(shù)據(jù)創(chuàng)建一個(gè)新的session對(duì)象,并返回
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
def save_session(
self, app: Flask, session: SessionMixin, response: Response
) -> None:
name = self.get_cookie_name(app)
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app)
# Add a "Vary: Cookie" header if the session was accessed at all.
if session.accessed:
response.vary.add("Cookie")
# If the session is modified to be empty, remove the cookie.
# If the session is empty, return without setting the cookie.
if not session:
if session.modified:
response.delete_cookie(
name,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
httponly=httponly,
)
response.vary.add("Cookie")
return
if not self.should_set_cookie(app, session):
return
expires = self.get_expiration_time(app, session)
val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore
response.set_cookie(
name,
val, # type: ignore
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
response.vary.add("Cookie")
-
SecureCookieSessionInterface
類:這個(gè)類實(shí)現(xiàn)了session接口,使用安全的簽名cookies來存儲(chǔ)session數(shù)據(jù)。 - 類屬性:
-
salt
:加鹽值,用于混淆session的加密過程,增加安全性。 -
digest_method
:哈希函數(shù),用于簽名過程中對(duì)數(shù)據(jù)進(jìn)行哈希處理,默認(rèn)為sha1。 -
key_derivation
:關(guān)鍵字派生,設(shè)置為"hmac",表示使用HMAC進(jìn)行簽名。 -
serializer
:序列化器,用于將Python對(duì)象轉(zhuǎn)換為可以在網(wǎng)絡(luò)上傳輸?shù)母袷剑@里使用的是JSON序列化器。 -
session_class
:表示session的類,默認(rèn)為SecureCookieSession。
-
-
get_signing_serializer
方法:用于獲取一個(gè)簽名序列化器,其作用是用來簽名和反簽名cookies的。如果應(yīng)用沒有設(shè)置秘鑰app.secret_key
,則返回None。 -
open_session
方法:在處理每個(gè)請(qǐng)求時(shí)調(diào)用,從請(qǐng)求的cookies中提取出session數(shù)據(jù),反序列化并驗(yàn)證簽名,得到session的數(shù)據(jù)。如果簽名不合法,就會(huì)拋出BadSignature
異常,然后返回一個(gè)空的session。 -
save_session
方法:在每個(gè)請(qǐng)求處理完后調(diào)用,將session數(shù)據(jù)序列化,簽名,然后存入到響應(yīng)的cookies中。如果session為空且已被修改,則刪除cookie。只有當(dāng)session被訪問過或被修改,才會(huì)設(shè)置Vary: Cookie
頭。
在使用SecureCookieSessionInterface
處理session時(shí),F(xiàn)lask會(huì)保證session的安全性,即使session數(shù)據(jù)存儲(chǔ)在客戶端的cookies中,也無法被篡改,因?yàn)槊總€(gè)session cookie都被簽名了。除非知道服務(wù)器的秘鑰,否則無法偽造有效的session cookie。文章來源地址http://www.zghlxwxcb.cn/news/detail-611899.html
到了這里,關(guān)于flask中的session介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!