Flask的cookie、session
七、設定cookies
from flask import Flask, make_response
app = Flask(__name__)
app.debug = True
@app.route('/', methods=['POST', 'GET'])
def index():
# 響應頭,新增make_response
response = make_response('ok')
# 設定cookies
response.set_cookie('key', 'val')
# 刪除cookies
response.delete_cookie("key")
# 設定響應頭
response.headers["x-somexx"] = "A SB"
return response
if __name__ == '__main__':
app.run()
7.1 設定cookie的引數
再設定cookie
的呼叫set_cookie()
時候傳入關鍵字實參 max_age= 值
,這個值
代表多少秒後過期。
注意:max_age引數設定過期時間不相容IE8一下的瀏覽器
...
@app.route('/')
def hello_world():
resp = Response('設定cookie給瀏覽器')
resp.set_cookie('user_name', 'mark',max_age=60)
# expires = datetime.now()+timedelta(days=30, hours=16)
# resp.set_cookie('user_name', 'mark', expires=expires) # 一個月過期時間
return resp
...
引數:
key, 鍵
value='', 值
max_age=None, 超時時間 cookie需要延續的時間(以秒為單位)如果引數是\ None`` ,這個cookie會延續到瀏覽器關閉為止
expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問,瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣可以避免將cookie傳給站點中的其他的應用。
domain=None, Cookie生效的域名 你可用這個引數來構造一個跨站cookie。如, domain=".example.com"所構造的cookie對下面這些站點都是可讀的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果該引數設定為 None ,cookie只能由設定它的站點讀取
secure=False, 瀏覽器將通過HTTPS來回傳cookie
httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)
7.2 查詢cookie
查詢cookie
是通過請求物件的cookies
屬性讀取,讀取的過程是使用設定cookie
時的key
來讀取到設定cookie
的value
...
@app.route('/get_cookie/')
def get_cookie():
user_name = request.cookies.get('user_name')
if user_name == 'mark':
return '{}的資訊'.format(user_name)
return 'cookie驗證失敗'
...
八、flask的session
session的基本概念:session又稱之為安全的cookie,session是一個思路、是一個概念、一個伺服器儲存授權資訊的解決方案,不同的伺服器,不同的框架,不同的語言有不同的實現,session的目的和cookie完全一致,cookie在客戶端和服務端處理的非常粗糙,cookie在瀏覽器儲存的時候以及傳輸的過程均使用明文,導致了很多安全隱患問題,session的出現就是為了解決cookie儲存資料不安全的問題。
注意:session是一個思路一個概念,session的實現是基於cookie的,session並不像cookie是一項真實存在的技術,可以簡單的理解為把粗糙的cookie在服務端通過加密,永久化等方式提高cookie的安全級別。
實現session的兩種思路
第一種
- 客戶端攜帶使用者資訊請求服務端驗證。
- 服務端驗證成功後生成隨機的session_id與使用者資訊建立對映後儲存到資料庫中(注意:資料庫可以是任意永久化儲存資料的機制,如redis、memcached、mysql、甚至是檔案等等)。
- 服務端把剛剛生成的session_id作為cookie資訊返回給客戶端。
- 客戶端收到以session_id為內容的cookie資訊儲存到本地。
- 客戶端再次請求的時候會攜帶以session_id為內容的cookie去訪問服務端,服務端取出session_id去資料庫校驗得到使用者資訊。
第二種(flask使用方式)
- 客戶端攜帶使用者資訊請求服務端驗證。
- 服務端收到使用者資訊驗證成功後,服務端再把使用者資訊經過嚴格的加密加鹽生成session資訊。並且把剛剛生成的session資訊作為cookie的內容返回給客戶端。
- 客戶端收到以session資訊為內容的cookie儲存到本地。
- 客戶端再次請求的時候會攜帶以session資訊為內容的cookie去訪問服務端,服務端取出session資訊經過解密得到使用者的資訊。
注意:flask使用的就是第二種思路,利用加密解密的方式實現session,實現安全的cookie,服務端並不會做永久化的儲存。
cookie:存放在客戶端的鍵值對
session:存放在客戶端的鍵值對
token:存放在客戶端,通過演算法來校驗
8.1 設定session(使用版)
Flask提供了session物件用來將cookie加密儲存,session通過祕鑰對資料進行簽名以加密資料。
from flask import Flask, session
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24) # 配置session使用的祕鑰
@app.route('/')
def set_session_info():
session['username'] = 'mark' # 使用使用者資訊配置sesion資訊作為cookie,並新增到響應體中
return '設定session資訊'
session物件像可以字典一樣操作,內部是把字典的資訊進行加密操作然後新增到相應體中作為cookie,響應的時候會自動返回給瀏覽器。
session['username'] = 'mark'
session['userphone'] = '123456' # 可以指定多條session資訊,統一放到響應的cookie中返回給瀏覽器
8.2 設定session(分析版)
在使用session之前必須現在設定一下金鑰
app.secret_key="asdas" # 值隨便
# app.config['SECRET_KEY'] = os.urandom(24) # 配置session使用的祕鑰
設定:session['username'] = 'xxx'
# 在django中發什麼三件事,1,生成一個隨機的字串 2 往資料庫存 3 寫入cookie返回瀏覽器
# 在flask中他沒有資料庫,但session是怎樣實現的?
# 生成一個金鑰寫入這個cookie,然後下次請求的時候,通過這個cookie解密,然後賦值給session
# 我們通過app.session_interface來檢視
刪除:session.pop('username', None)
from flask import Flask,session
app = Flask(__name__)
# 要用session,必須app配置一個金鑰
app.secret_key = "asdasdihasdiuh"
# 設定session的名字,預設配置檔案中為:session
app.config['SESSION_COOKIE_NAME']="python13session"
# app.session_interface
#app.session_interface實現了兩個方法,一個叫save_session,一個open_session,
# save_session 存session執行,加密設定cookies
# open_session 取session執行,解密大字典,拿到session
@app.route("/",)
def index():
#如何設定sessoion
# 1 匯入session
# 2 給sessoion設定值
session['name'] = "egon"
return "ok"
@app.route("/login")
def login():
print(session["name"])
return "login"
if __name__ == '__main__':
app.run()
8.3 設定session有效期
後端Flask跟瀏覽器互動預設情況下,session cookie會在使用者關閉瀏覽器時清除。通過將session.permanent屬性設為True可以將session的有效期延長為31天,也可以通過操作app的配置PERMANENT_SESSION_LIFETIME來設定session過期時間。
案例 3.3.2.1:開啟指定session過期時間模式
from flask import Flask, session
import os
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
@app.route('/')
def set_session_info():
session['username'] = 'mark'
session['userphone'] = '123456'
session.permanent = True # 開啟設定有效期,預設為31天后過期
return 'Hello World!'
...
設定自定義過期時間
# 通過設定PERMANENT_SESSION_LIFETIME指定具體的過期時間
from datetime import timedelta
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1) # 設定為1小時候過期
8.4 獲取sessoin
在Flask中獲取設定的session資訊通過session物件獲取,session物件是繼承了字典類,所以獲取的時候是字典的取值方式。其內部會把瀏覽器傳過來的session資訊解密。
@app.route('/get_session/')
def get_session():
username = session.get('username')
userphone = session.get('userphone')
if username or userphone:
return "{},{}".format(username, userphone)
return "session為空"
8.5 刪除session
session
物件呼叫pop()
可以根據具體的session
的key清除掉指定的session資訊。
session物件呼叫clear()
可以清除此次請求的瀏覽器關於本域名的所有session資訊
@app.route('/del_session/')
def del_session():
session.pop('username')
# session.clear()
return '刪除成功'
8.6 原始碼分析
session原始碼的執行流程
-save_seesion
-響應的時候,把session中的值加密序列化放大到了cookie中,返回到瀏覽器中
-open_session
-請求來了,從cookie中取出值,反解,生成session物件,以後再檢視函式中直接用sessoin就可以了。
原始碼分析
# app.session_interface 點進去
class SecureCookieSessionInterface(SessionInterface):
salt = "cookie-session"
digest_method = staticmethod(hashlib.sha1)
key_derivation = "hmac"
serializer = session_json_serializer
session_class = SecureCookieSession
def get_signing_serializer(self, app):
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,
)
# 取session的時候執行的
def open_session(self, app, request):
s = self.get_signing_serializer(app)
if s is None:
return None
##cookie鍵是SESSION_COOKIE_NAME"=session
val = request.cookies.get(app.session_cookie_name)
print("open_session.session_cookie_name,", app.session_cookie_name, )
if not val:
return self.session_class()
max_age = total_seconds(app.permanent_session_lifetime)
try:
data = s.loads(val, max_age=max_age)
print("self.session_class(data)", self.session_class(data) )
return self.session_class(data)
except BadSignature:
return self.session_class()
#存session的時候執行的
def save_session(self, app, session, response):
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
# 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(
app.session_cookie_name, domain=domain, path=path
)
return
# Add a "Vary: Cookie" header if the session was accessed at all.
if session.accessed:
response.vary.add("Cookie")
if not self.should_set_cookie(app, session):
return
httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
expires = self.get_expiration_time(app, session)
# 把session做了一個加密,把整個session的key--》val,全部加密,的到一個value值,
#session是一個大字典,
val = self.get_signing_serializer(app).dumps(dict(session))
# 他把session加密後得到的val存到cookie裡面了
#cookie鍵是SESSION_COOKIE_NAME"=session
print("原始碼中的session",dict(session))
print("app.session_cookie_name,",app.session_cookie_name,)
response.set_cookie(
app.session_cookie_name,
val,
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)