爲何說session依賴cookie,以及cookie的經常使用知識

session的用法

session在Flask中一般用作設置某些頁面的權限,好比某些頁面必需要登陸才能夠看到,登陸的信息或標誌就放到session中.它的使用過程以下:html

  1. 在整個flask工程的啓動文件中添加app.config['SECRET_KEY'] = 'you never guess',SECRET_KEY是用來加密session的,本質上是一個加密鹽.
  2. 再在使用的py文件中添加from functools import wraps ,封裝裝飾器
  3. 在使用的py文件中添加from flask import session
  4. 而後寫處理函數
  5. 再在邏輯代碼中寫已經登陸的標誌或者是存儲其餘關於請求的信息
  6. 最後在設置限制的視圖函數前添加限制函數的修飾器

一個簡單的例子

# 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存在的.python

  1. cookie存在的目的:chrome

    由於http協議屬於無狀態協議,它不跟蹤從一個客戶端到另外一個客戶端的請求信息.也就是說即便第一次和服務器鏈接後而且登陸成功,第二次請求服務器依然不知道請求的是哪一個用戶.
    因此使用cookie來解決這個問題:第一次登陸成功後,服務器返回cookie給瀏覽器,而後瀏覽器保存在本地,當用戶發送第二次請求時,就會自動的把上次請求存儲的cookie數據攜帶給服務器,服務器再根據cookie數據判斷是哪一個用戶.shell

  2. session和cookie的做用相似:
    也是用來存儲用戶相關的信息,存儲在服務器端.把用戶的信息通過加密後存儲在session中,而後產生一個惟一的session_id.flask

  3. 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。

擴展

  1. 既然session依賴cookie,要是瀏覽器禁用了cookie改怎麼達到狀態保持的效果呢?
    這個時候,就須要用到URL重寫了,既讓服務器收到的每一個請求參數中都帶有sessioinId,也就是從本來的隱式(headers傳參)變爲url或body傳參。

  2. 當咱們清空瀏覽器的時候,session會消失嗎?
    這個問題包含着一些陷阱。由於不少時候當咱們清空瀏覽器之後,確實須要從新登陸系統才能夠操做,因此不少人天然而然認爲清空瀏覽器緩存(包含cookie)之後session就會消失。
    其實這種結論是錯誤的。要知道,session是存在於服務器的,你清除瀏覽器緩存,只是清除了cookie,跟session一點關係都沒有。那麼爲何咱們卻不能訪問網站,而須要從新登陸了呢?由於清空了瀏覽器緩存,這時候cookie數組中一定不會有JSESSIONID這個cookie,因此必須得新建一個session,用新的sessionId來給JSESSIONID這個cookie賦值。因爲是新建的session,session中一定沒有userId這樣的屬性值,因此判斷結果天然爲空,因此須要從新登陸。此次賦值之後,下一次再請求該網站的時候,因爲cookie數組中已經有了JSESSIONID這個cookie,而且能經過該JSESSIONID的值找到相應的session,因此就不須要再從新登陸了。

參考

  1. http://www.pythondoc.com/flask/config.html
  2. https://blog.csdn.net/qq_37526590/article/details/80219227
  3. https://www.cnblogs.com/keyi/p/6823853.html
相關文章
相關標籤/搜索