session的用法
session在Flask中通常用做設置某些頁面的權限,比如某些頁面必須要登錄才可以看到,登錄的信息或標志就放到session中.它的使用過程如下:
- 在整個flask工程的啟動文件中添加app.config['SECRET_KEY'] = 'you never guess',SECRET_KEY是用來加密session的,本質上是一個加密鹽.
- 再在使用的py文件中添加from functools import wraps ,封裝裝飾器
- 在使用的py文件中添加from flask import session
- 然后寫處理函數
- 再在邏輯代碼中寫已經登錄的標志或者是存儲其他關於請求的信息
- 最后在設置限制的視圖函數前添加限制函數的修飾器
一個簡單的例子
# encoding: utf-8
from flask import Flask
from flask import request, session, redirect
from functools import wraps
app = Flask(__name__)
app.config['SECRET_KEY'] = 'you never guess' # 使用 session 必須要配置這個,加密簽名.
# 登錄、注冊認證函數
def authorize(fn):
@wraps(fn)
def wrapper(*args, **kwargs): # 這里就像過濾器,有了那個修飾器標志的視圖函數都必須經過這個函數才可以返回請求
user = session.get('logged_in', None) # 取得登錄標志
if user:
return fn(*args, **kwargs) # 登錄了就返回請求
else:
return 'need login!' # 否則就轉到注冊的頁面
return wrapper
@app.route('/')
@app.route('/home')
def index():
session["global_name"] = "global_path"
return session["global_name"] + 'home.html'
@app.route('/find')
def find():
print(vars(session))
return session.get("global_name", "None") + 'find.html'
@app.route('/doc')
@authorize # 這個修飾器表示,這個視圖頁面必須登錄才可以訪問
def blog():
print(session['username'])
return 'blog.html'
# 登錄用戶
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return "login.html"
if request.method == 'POST':
username = request.values.get('username')
password = request.values.get('password')
if username and password:
session['logged_in'] = True # 登錄成功
session['username'] = username
session['password'] = password
return username + password
else:
return "need username and password"
# 注銷用戶
@app.route('/signout', methods=['GET', 'POST'])
@authorize
def logout():
session['logged_in'] = False # 變成false 就意味着需要重新登錄了
return redirect('/home')
if __name__ == '__main__':
app.run()
幾句curl
# 登錄接口與返回,可以看出response中set-cookie了
curl -X POST "http://127.0.0.1:5000/login" -d "username=test&password=123"
HTTP/1.0 200 OK
Set-Cookie: session=eyJsb2dnZWRfaW4iOnRydWUsInBhc3N3b3JkIjoiMTIzIiwidXNlcm5hbWUiOiJsZ2oifQ.DoNGjg.4c2Adke_tzqo5MW_BHs95FvY6i4; HttpOnly; Path=/
# 不帶cookie訪問需要登錄的接口
curl "http://127.0.0.1:5000/doc"
need signin!
# 帶上cookie后訪問通過
curl --cookie "session=eyJsb2dnZWRfaW4iOnRydWUsInBhc3N3b3JkIjoiMTIzIiwidXNlcm5hbWUiOiJsZ2oifQ.DoNGjg.4c2Adke_tzqo5MW_BHs95FvY6i4" "http://127.0.0.1:5000/doc"
user/blog.html
# 登出接口也是同上的.
curl "http://127.0.0.1:5000/logout"
need signin!
curl --cookie "session=eyJsb2dnZWRfaW4iOnRydWUsInBhc3N3b3JkIjoiMTIzIiwidXNlcm5hbWUiOiJsZ2oifQ.DoNGjg.4c2Adke_tzqo5MW_BHs95FvY6i4" "http://127.0.0.1:5000/signout"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/home">/home</a>. If not click the link.
# 使用session存儲一些其他信息也是依賴於cookie存在的
curl -v "http://127.0.0.1:5000"
global_pathhome.html
HTTP/1.0 200 OK
Set-Cookie: session=eyJnbG9iYWxfbmFtZSI6eyIgYiI6IloyeHZZbUZzWDNCaGRHZz0ifX0.DoNPag.ooEMHsinZlKRQpLF_-S3axsH3jc; HttpOnly; Path=/
# 想要得到設置global_name,不帶cookie是得不到的
curl "http://127.0.0.1:5000/find"
Nonefind.html
# 帶cookie
curl --cookie "session=eyJnbG9iYWxfbmFtZSI6eyIgYiI6IloyeHZZbUZzWDNCaGRHZz0ifX0.DoNPag.ooEMHsinZlKRQpLF_-S3axsH3jc" "http://127.0.0.1:5000/find"
global_pathfind.html
# 設置cookie
curl -v "http://127.0.0.1:5000/set_cookie"
< HTTP/1.0 200 OK
< Set-Cookie: name=test; Expires=Wed, 19-Sep-2018 03:42:31 GMT; Max-Age=200; Path=/
< Set-Cookie: age=18; Path=/
set_cookie* Closing connection 0
# 獲取cookie
curl --cookie "name=test;age=18" "http://127.0.0.1:5000/get_cookie"
name is test,name is 18
總結:
平時使用瀏覽器訪問接口,很難注意到cookie和session的區別與聯系,使用curl就把區別暴露了出來.
上面的curl交互可以看出 session是會以set-cookie的方式設置到瀏覽器中,之后的訪問都會將cookie帶上請求其他接口,若使用curl而不帶上cookie就會導致錯誤,這也是為什么說session是依賴cookie存在的.
-
cookie存在的目的:
因為http協議屬於無狀態協議,它不跟蹤從一個客戶端到另一個客戶端的請求信息.也就是說即使第一次和服務器連接后並且登錄成功,第二次請求服務器依然不知道請求的是哪個用戶.
所以使用cookie來解決這個問題:第一次登錄成功后,服務器返回cookie給瀏覽器,然后瀏覽器保存在本地,當用戶發送第二次請求時,就會自動的把上次請求存儲的cookie數據攜帶給服務器,服務器再根據cookie數據判斷是哪個用戶. -
session和cookie的作用類似:
也是用來存儲用戶相關的信息,存儲在服務器端.把用戶的信息經過加密后存儲在session中,然后產生一個唯一的session_id. -
cookie和session的結合使用
一般有兩種存儲方式:
(1) 存儲在服務器端:通過cookie存儲一個session_id,然后具體的數據則是保存在session中.如果用戶已經登錄,則服務器會在cookie中保存一個session_id,下次再請求時,會把該session_id攜帶上來,服務器根據session_id在session庫中獲取用戶的session數據,就知道用戶到底是誰了.以及之前保存的一些狀態信息,這種專業術語叫做server side session. (2) 存儲在客戶端:將session數據加密,然后存儲在cookie中.這種專業術語叫做 client side session.flask框架采用的就是這種方式,但是可以替換成其他形式.
flask的session機制
把用戶信息經過加密后放入到session中,然后把session存放到cookie中.下次請求時,從瀏覽器發送過來的cookie中讀取到session,然后再從session中讀取數據並解密,獲取最終的用戶數據.這樣可以節省服務器開銷.
cookie的刪除
1) 可以通過在瀏覽器中設置來清除cookie.
(2) 使用Response的set_cookie進行清除
@app.route('/del_cookie')
def del_cookie():
response=make_response('delete cookie')
response.set_cookie('Name','',expires=0)
return response
(3)使用Response的 delete_cookie方法.
@app.route('/del_cookie2')
def del_cookie2():
response=make_response('delete cookie2')
response.delete_cookie('Name')
return response
cookie的其他屬性
觀察"Set-Cookie: name=test; Expires=Wed, 19-Sep-2018 03:42:31 GMT; Max-Age=200; Path=/" 可以看出其實cookie有很多屬性,如下:
在chrome控制台中的resources選項卡中可以看到cookie的信息。
一個域名下面可能存在着很多個cookie對象。
name 字段為一個cookie的名稱。
value 字段為一個cookie的值。
domain 字段為可以訪問此cookie的域名。
非頂級域名,如二級域名或者三級域名,設置的cookie的domain只能為頂級域名或者二級域名或者三級域名本身,不能設置其他二級域名的cookie,否則cookie無法生成。
頂級域名只能設置domain為頂級域名,不能設置為二級域名或者三級域名,否則cookie無法生成。
二級域名能讀取設置了domain為頂級域名或者自身的cookie,不能讀取其他二級域名domain的cookie。所以要想cookie在多個二級域名中共享,需要設置domain為頂級域名,這樣就可以在所有二級域名里面或者到這個cookie的值了。
頂級域名只能獲取到domain設置為頂級域名的cookie,其他domain設置為二級域名的無法獲取。
path 字段為可以訪問此cookie的頁面路徑。 比如domain是abc.com,path是/test,那么只有/test路徑下的頁面可以讀取此cookie。
expires/Max-Age 字段為此cookie超時時間。若設置其值為一個時間,那么當到達此時間后,此cookie失效。不設置的話默認值是Session,意思是cookie會和session一起失效。當瀏覽器關閉(不是瀏覽器標簽頁,而是整個瀏覽器) 后,此cookie失效。
Size 字段 此cookie大小。
http 字段 cookie的httponly屬性。若此屬性為true,則只有在http請求頭中會帶有此cookie的信息,而不能通過document.cookie來訪問此cookie。
secure 字段 設置是否只能通過https來傳遞此條cookie
下面是flask中cookie對應屬性的配置項
SECRET_KEY 密鑰
SESSION_COOKIE_NAME 會話 cookie 的名稱
SESSION_COOKIE_DOMAIN 會話 cookie 的域。如果沒有設置的話, cookie 將會對 SERVER_NAME 所有的子域都有效。
SESSION_COOKIE_PATH 會話 cookie 的路徑。如果沒有設置或者沒有為 '/' 設置,cookie 將會對所有的 APPLICATION_ROOT 有效。
SESSION_COOKIE_HTTPONLY 控制 cookie 是否應被設置 httponly 的標志, 默認為 True 。
SESSION_COOKIE_SECURE 控制 cookie 是否應被設置安全標志,默認為 False。
擴展
-
既然session依賴cookie,要是瀏覽器禁用了cookie改怎么達到狀態保持的效果呢?
這個時候,就需要用到URL重寫了,既讓服務器收到的每個請求參數中都帶有sessioinId,也就是從原本的隱式(headers傳參)變為url或body傳參。 -
當我們清空瀏覽器的時候,session會消失嗎?
這個問題包含着一些陷阱。因為很多時候當我們清空瀏覽器以后,確實需要重新登錄系統才可以操作,所以很多人自然而然認為清空瀏覽器緩存(包含cookie)以后session就會消失。
其實這種結論是錯誤的。要知道,session是存在於服務器的,你清除瀏覽器緩存,只是清除了cookie,跟session一點關系都沒有。那么為什么我們卻不能訪問網站,而需要重新登錄了呢?因為清空了瀏覽器緩存,這時候cookie數組中必定不會有JSESSIONID這個cookie,所以必須得新建一個session,用新的sessionId來給JSESSIONID這個cookie賦值。由於是新建的session,session中必定沒有userId這樣的屬性值,所以判斷結果自然為空,所以需要重新登錄。這次賦值以后,下一次再請求該網站的時候,由於cookie數組中已經有了JSESSIONID這個cookie,並且能通過該JSESSIONID的值找到相應的session,所以就不需要再重新登錄了。