Web技術:Token與Session究竟是什麼呢

胖琪的升級之路發表於2019-02-13

前言

在web中,我們經常說session,token,cookie。這三個內容,究竟啥區別,為什麼會有這三個內容呢?這就是我們今天想要討論的。

故事,美好的開始

洋洋: 琪琪,你們原先的開發 許可權是怎麼認證的?

琪琪: 許可權?不就是攔截器嘛?通過攔截不同的url,進行攔截,然後進行校驗。

洋洋: 那你們用過shiro嘛?進行許可權校驗的。

琪琪: 那個倒是沒用過,我原先了解是用token做的,然後再造輪子寫許可權。

洋洋: 哦哦那你講下session與token 是啥?我還是有點不明白呢,你們當初是怎麼設計的?

故事開始了

既然要說 session 與token,順便了解下cookie?

cookie

co哥: 該我出場提問了。第一個問題: 為什麼要有cookie? 琪琪: 為什麼要有呢?(小樣,竟然問我這麼簡單的問題)。有它不就是為了儲存web中的狀態資訊嘛,方便服務端使用嘛。

co哥:那cookie 一般是怎麼擁有的?客戶端可以建立嘛? 琪琪:我們都說cookie存在於客戶端,如果不是篡改的問題,cookie第一次是伺服器向客戶端傳送的

co哥:你說的對,順便再加一個就是我們的瀏覽器也會將cookie儲存,並且每次請求後也把這些資訊傳送給服務端哦。

琪琪: 恩?那傳送的是什麼格式呢?(自問自答怎麼樣?)有什麼限制嗎?

琪琪: cookie嗎? 簡單說就是遵循name=value 格式的字串。還有就是4kB的大小限制,cookie中其他內容就是可選項了。

琪琪: 還有一點就是set-cookie是在header中哦.

順便提供下主要構成嗎,大家可以看下。

name:一個唯一確定的cookie名稱。通常來講cookie的名稱是不區分大小寫的。

value:儲存在cookie中的字串值。最好為cookie的name和value進行url編碼

domain:cookie對於哪個域是有效的。所有向該域傳送的請求中都會包含這個cookie資訊。這個值可以包含子域(如:yq.aliyun.com),也可以不包含它(如:.aliyun.com,則對於aliyun.com的所有子域都有效).

path: 表示這個cookie影響到的路徑,瀏覽器跟會根據這項配置,像指定域中匹配的路徑傳送cookie。

expires:失效時間,表示cookie何時應該被刪除的時間戳(也就是,何時應該停止向伺服器傳送這個cookie)。如果不設定這個時間戳,瀏覽器會在頁面關閉時即將刪除所有cookie;不過也可以自己設定刪除時間。這個值是GMT時間格式,如果客戶端和伺服器端時間不一致,使用expires就會存在偏差。

max-age: 與expires作用相同,用來告訴瀏覽器此cookie多久過期(單位是秒),而不是一個固定的時間點。正常情況下,max-age的優先順序高於expires。

HttpOnly: 告知瀏覽器不允許通過指令碼document.cookie去更改這個值,同樣這個值在document.cookie中也不可見。但在http請求張仍然會攜帶這個cookie。注意這個值雖然在指令碼中不可獲取,但仍然在瀏覽器安裝目錄中以檔案形式存在。這項設定通常在伺服器端設定。

secure: 安全標誌,指定後,只有在使用SSL連結時候才能傳送到伺服器,如果是http連結則不會傳遞該資訊。就算設定了secure 屬性也並不代表他人不能看到你機器本地儲存的 cookie 資訊,所以不要把重要資訊放cookie就對了
複製程式碼

session 你來了?

wa: 既然有了cookie,那為什麼還出來session了?這是做什麼的?

session 生成

瀏覽器第一次訪問伺服器的時候,伺服器會建立一個session,同時生成唯一的key,則是sessionID。

琪琪: 小黑板來了,我來提問了,第一次訪問,那多個瀏覽器使用同一個賬戶資訊,伺服器不做其他限制,那是不是形成多個session呢?

wa: 當然了,每次訪問都會形成一個新的sessionID,那就是session不一樣了.這樣相當於session 都保持這次會話訪問的連線。

琪琪:會話訪問的連線?那就代表有狀態了哦。 那在後端是怎麼把session返回給客戶端的?

wa: 通過設定cookie的方式返回給客戶端哦。當然在後端的時候我們也可以將session儲存到資料庫或者redis這些nosql中。

琪琪:我們通過cookie傳送了。但有時候瀏覽器禁止cookie怎麼辦?

wa: 這個嘛?我想想...(你說你問這麼多幹嘛,還得費腦子)。可以通過URL重寫的方式傳送給伺服器哦。

琪琪: 這也對。但還有個問題,如果我們後臺有個伺服器部署,屬於分散式的,那我再其中一臺登入了,稱為A,session也儲存到A中,萬一下次我訪問到另外一臺伺服器B怎麼辦?B上沒有A的session呢。

wa: enenen ? 你問我?我也不知道。

le: 來來,我說下吧。可以這樣嘛,既然每個伺服器都有session,那我們就儲存到庫裡面算了。這樣我們就能互相通過訪問過來的cookie 裡拿到session資訊與庫中的進行對比。session 就共享了。

2019-02-13-23-38-44
wa: 是哦,通過資料庫或者nosql 進行處理了,但這樣不就出現另外一個問題,我們需要儲存這些資料,如果數量小點還好說資料量大了這些內容不也就帶來效能問題?

le: 嗯呢,所以叢集,出來了,所以每次儲存這些session資訊就是一個負擔了。這就是我們需要在系統設計的時候考慮,狀態資訊需要儲存嘛?

session的終結者,token你選擇嘛?

session 是儲存了會話的連結資訊與我們需要傳輸的內容,容量大,還需要保持會話資訊,每次同一使用者不同客戶端訪問我都需要重新建立session,造成冗餘資訊大。

ff: 這該怎麼辦呢,真不想儲存。

琪琪:這還不簡單,那就不儲存了,採用token吧?

ff: token? 那是個啥?

琪琪: ennnn,那不是啥。那是一個新技術,被稱為令牌的東西。

ff: 那token能驗證使用者的合法性嘛?

琪琪: ...當然,比如使用者登入了,我們會把令牌資訊,傳送給他,包含了一個他的userId,代表他的資訊,再訪問的時候通過header或者bady帶過來就好。

ff: 感覺與sessionID沒有區別呢? 咦,貌似不用儲存session資訊到庫裡面了,還有每次不同的會話建立新的token,也不影響(單點登入貌似可以通過token做哦,做過的小夥伴可以嘗試下)。好神奇。

琪琪: 是的,是不是感覺token比session好多了?

ff: ennnn,但這不是給黑客創造了偽造的 token資訊嘛?怎麼防止這些資訊呢?

琪琪: 這還不簡單,對我們們返回的token裡面資料做一個簽名,祕鑰別人不知道,這樣偽造的token不就通不過我們的限制了嘛。加密演算法可以採用HMAC-SHA256這些演算法了etc.

ff :神奇的token啊。這就解決session 這些問題了。

session與token 故事完了嗎?

嘿嘿,怎麼能結束呢,只說了理論,但還有很多問題沒解決呢。就讓琪琪一個個提問吧。

wa: 先不提問,我再說幾個結論,在提問。。

  • token 是無狀態的,後端不需要記錄資訊,每次請求每次解密就行。
  • session 是有狀態的,需要後端每次去檢索id的有效性。不同的session都需要進行儲存哦。但讓也可以設定單點登入,減少儲存的資料。
  • session與token的問題是空間與時間博弈,為什麼這麼說呢,是因為token不需要儲存,直接獲取,每次訪問都需要進行解密。

好了就先說這幾條吧,以後有了在補充。

琪琪:總結了這麼多了,那我們開始提問了。首先,為啥客戶端ios與Andriod基本上沒見過用session的?

ff: 這個我來回答吧。因為在這些客戶端上啊,原生介面都是每一次建立一個會話,這就出問題了,這樣會導致登入功能失效了,登入每次把資訊放到session中,session都不一樣了,每次登入都成新的一個人了,這就不ok了。

琪琪:哦哦原來客戶端是每次用原生介面都是新建立一個會話,好尷尬的設計。那我們採用什麼方式解決這個問題呢?

ff: 在使用者登入後,重點哦我們可以通過cookie嘛,我們在app端也可以是儲存cookie的,我們知道cookie將sessionID儲存好,返回給客戶端,伺服器最後也是通過SessionId來標識的。但是利用token的話,內容我們可以自定義,並且不用再服務端進行儲存。方便我們處理。

琪琪:那麼就是token可以儲存到cookie中,如果禁止的話我們也可以儲存到body中每次都請求上或者header中。

總結

恩,token,cookie,session的內容就到這裡的,不同的方案都有各個的區別,當然從這裡看我門瞭解的還是不不夠多,需要繼續努力

歡迎大家關注公眾號LuckQI.

LuckQI

相關文章