以前遇到一位老面試官,問個人問題真的有點東西

這篇文章其實源於一次個人面試經歷。java

那次我面對是一位老面試官,真的頗有東西。web

那次面試我和他叨叨了兩小時....我滴媽我嘴巴都幹了真的。面試

他的提問都頗有深度,能夠說對個人學習之路有很大的幫助。跨域

我記得有個問題,差很少是面了一個小時的時候他問我:Cookie、Session、Token知道的吧?瀏覽器

我說:知道。安全

那你從演進的角度來說講 Cookie 、Session、Token?服務器

我當時就懵了,單獨的說我都清楚,這演進的角度讓我一下不知從何提及。微信

這個面試官會從各個角度去感覺我對一個知識點究竟是背的,仍是有本身理解的。網絡

他提問的方式真的頗有東西,他也給我反饋了不少他的理解,相談甚歡,真的。session

就這個問題他從 HTTP 無狀態開始慢慢的引導我.....

他的這波引導其實就串聯起了這一系列的知識點,零散的東西就被他整理的明明白白。

因此後來的學習我都喜歡找原因,也就是爲何。

也是我一直強調的要知道:爲何會有這個東西的存在,這個的東西是爲了解決什麼痛點。

起初是由於我怕面試官再問我這樣的問題。

如今是由於就應該這樣學。

今兒就來捋捋以前面試官問個人這個題的。

正文

1990 年。

蒂姆·伯納斯·李建立了 HTTP 協議。

李老的想法是把文檔存儲在服務器中,誰須要這個文檔直接從服務器獲取便可。

按照這個思想,當時的需求只有 GET。

而且按照拿文檔的思路:拿完了鏈接就能夠斷了,也不須要什麼交互。

因此 HTTP 起初的設計就是無狀態的。

也就是請求和請求之間是沒有關聯的。

而隨着互聯網的發展,交互開始興起。

人們再也不知足簡單的靜態文件獲取,各類購物、社交接踵而至。

這意味着服務器須要判斷每一個請求的發起者是誰,也就是須要狀態。

你聊天總得代表你是誰,而且和誰聊吧?否則服務器可不知這聊天信息得發給誰。

你購物總得讓服務器知道是誰買了這玩意吧?

總不能你買完了下線,再上線發現你買的東西沒了。

這時候就是須要一種技術讓請求與請求之間創建起聯繫,讓請求變得有狀態。

這技術叫 Cookie,就是一個以 Key-Value 格式存儲的小文件,保存在客戶端本地

好比登陸以後,服務器就能設置 Cookie 返回給瀏覽器,而後保存在本地。

隨便截了個百度的,列出來的就是 key,下拉箭頭打開裏面就有 value。

以後對百度的請求就能夠帶着 Cookie 去訪問服務器,這裏假設 BAIDUID 是用戶 ID。

百度的服務器一看原來是這個 ID 啊,就知道是「我」請求了,這就有狀態了。

簡單地說 Cookie 就是存儲在本地的一份文件,每次請求都會帶上 Cookie 去訪問服務器。

因此把一些用戶信息塞到 Cookie 裏,這樣服務器就能判別是哪一個用戶的請求了

注意 Cookie 是有域的劃分的,來看下這個圖:

也就是每一個域下面都有各自的 Cookie ,訪問不一樣的網站帶屬於這個網站的 Cookie ,不會帶別人的 Cookie ,否則就亂套了。

可是 Cookie 是明文存儲在用戶本地,並且帶有大量的用戶信息這不太安全。

而且每次請求都須要帶這麼多 Cookie 對帶寬來講也不太划算。

Session 就解決了這個問題,Session 就是會話,它有更加普遍的含義,在和 Cookie 這些一塊兒談論的場景,咱們把它狹義化。

Session 就是把用戶的會話信息存儲在服務端。

而後頒發給客戶端一個 sessionId,讓客戶端以後帶着 sessionId 來請求。

這樣服務端就能夠經過 sessionId 去找到這個用戶的信息,從而識別請求。

那客戶端是如何帶上 sessionId 的?

這個 sessionId 仍是按照 Cookie 的形式存儲在用戶的本地,發起請求的時候帶上便可。

可是把這種狀態信息存儲到服務器中使得服務器就有狀態了

通常咱們部署在線上的服務器會有多臺來作負載均衡,也互相做爲 backup。

因此若是 Session 的信息存在某一臺機器上,那麼當下一次請求被負載分到另外一臺機器那就找不到這個 Session 信息了。

也就不認得這個請求了,可能的現象就是告訴用戶沒登陸,那用戶不就傻了。

我這剛還登陸着呢,這就告訴我沒登陸了?

因此處理方式有 session 複製,就是服務器之間互相同步 session,這樣不論請求到哪一個服務器都有用戶的信息。

不過這複製就冗餘了,有額外的開銷。

還有一種就是 session sticky,其實就是把你的請求一直粘在某一個服務器上,若是你請求的一開始被指派的是 A 服務器,那麼以後的全部請求都只會被指派到 A 服務器上。

可是若是 A 服務器掛了,你的請求仍是會被指派到別的服務器上,這樣一來用戶登陸信息仍是會丟了。

能夠看到複製和 sticky 都有缺陷,因此能夠把 session 放到第三方存儲,好比 Redis 裏。

這樣服務器等於又沒狀態了。

而服務器的無狀態意味着能夠隨意伸縮,服務集羣根據流量加幾臺減幾臺,很方便。

可是把 session 放第三方存儲上只是把這個維護從服務器轉嫁到第三方身上。

第三方得保證它的高可用,否則用戶登陸信息又會丟了。

不過通常而言咱們的系統原本就要維護的第三方存儲,因此影響不大。

小結一下:Cookie 明文存儲在本地不太安全,因此想着把用戶狀態存在服務端,而 Session 就是將用戶狀態信息保存在服務端。

就暴露 sessionId 給客戶端,這樣相對而言安全些,而且也減小了網絡流量。

但這樣服務端就有狀態了,難以擴展。

所以能夠把 Session 放到第三方存儲上,可是等於狀態仍是由服務端維護。

Token

其實仔細想一想,是否是不須要在服務端存儲用戶的信息?

只須要一個能表明身份的憑證便可,一個服務端頒發給用戶憑證,以後的請求讓用戶帶着這個憑證就行。

就像咱們的身份證,就表明咱們。

這個憑證裏面就包含了用戶的信息,有人可能怕憑證被僞造。

沒事,把憑證給簽名了,這樣咱們服務器就能驗證憑證的真僞。

和別人作不得假身份證同樣。

這種憑證叫 Token。

若是一個用戶登陸了系統,我就返回一個 Token 給他,以後每次請求他帶着這個 Token 來就行。

服務器驗證了真僞以後拿到 Token 裏面的用戶信息就知道這個請求是誰發的了。

這樣服務器就無狀態了,是真的無狀態了,固然客戶端有狀態了。

由客戶端來保存 Token ,這樣是最合理的,不須要在服務端冗餘數據。

有了 Token 以後服務器由於無狀態因此可擴展,而且 Token 還能跨應用使用。

好比同一個公司不一樣應用之間的調用,全部應用只要能識別這個 Token 就都能登陸。

一個 Token 就搞定了,不用每一個網站都登陸一遍,這就是單點登陸。

若是是第三方服務提供方也更容易地提供服務,只須要頒發一個 Token 給調用者便可。

Token  簡單的說就是一個含有憑證信息的令牌,只要服務器能識別這個令牌就能根據令牌的身份進行相應的響應。

其實這還蘊含了時間換空間的思想,把存儲在服務器的用戶信息暴露出去,利用簽名來驗證 Token 的真僞。

這樣每次請求都須要耗費時間去驗籤,不過好處就是不須要存儲信息,也就是時間換空間。

最後

其實像 Cookie + Session 除了可擴展還有跨域啊、跨站僞造請求等問題。

像 Token 更加靈活,在移動端等場景也更加的適用。

有關文章所講的演進看起來好像就是 Cookie => Session =>Token

不是的,這幾個東西都頗有用,文章只是單從認證這一方面來看罷了

歡迎加我好友進行深刻地交流,備註「進羣」,拉你進交流&內推羣。

平日的面試題遇到難處,或者看某個知識點翻遍全網的資料仍是感受很模糊、不透徹,能夠私聊我,給我留言。

遇到合適的我會整理寫出一篇文章,注意這個前提我認爲合適的。

那種工做遇到很細節的場景的仍是別了,這種問你上司比較合適:)。


我是 yes,從一點點到億點點,歡迎在看、轉發、留言,咱們下篇見。


本文分享自微信公衆號 - yes的練級攻略(yes_java)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索