session token徹底弄懂各自應用場景

先講講起源:

HTTP是一個基于TCP/IP通信協議來傳遞數據(HTML 文件, 圖片文件, 查詢結果等)。
無連接:無連接的含義是限制每次連接只處理一個請求。
服務器處理完客戶的請求,并收到客戶的應答后,即斷開連接。采用這種方式可以節省傳輸時間。
無狀態:HTTP協議是無狀態協議。無狀態是指協議對于事務處理沒有記憶能力。缺少狀態意味著如果后續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。另一方面,在服務器不需要先前信息時它的應答就較快。
郵件服務器很羨慕我, 他說:老弟,你的生活太愜意了, 哪像我, 每次有人從客戶端訪問郵箱, 我都得專門給他建立一個會話, 來處理他發的消息, 你倒好, 完全不用管理會話。

這是由應用的特性決定的, 如果郵件服務器不管理會話, 那多個人之間的郵件消息就會完全混到一起了, 亂作一團了。

而30年前的Web 基本上就是文檔的瀏覽而已, 既然是瀏覽,我作為一個服務器, 為什么要記住誰在一段時間里都瀏覽了什么文檔呢?

session

但是好日子沒持續多久, 很快大家就不滿足于靜態的Html 文檔了, 交互式的Web應用開始興起, 尤其是論壇, 在線購物等網站。

我馬上就遇到了和郵件服務器一樣的問題, 那就是必須管理會話,必須記住哪些人登錄系統, 哪些人往自己的購物車中放了商品, 也就是說我必須把每個人區分開。

這對我來說是個不小的挑戰, 由于HTTP協議的無狀態特性, 我必須加點小手段,才能完成會話管理。

我想出的辦法就是給大家發一個會話標識(session id), 說白了就是一個隨機的字符串,每個人收到的都不一樣, 每次大家向我發起HTTP請求的時候,把這個字符串給一并捎過來, 這樣我就能區分開誰是誰了。
服務器創建session出來后,會把session的id號,以cookie的形式回寫給客戶機,這樣,只要客戶機的瀏覽器不關,再去訪問服務器時,都會帶著session的id號去,服務器發現客戶機瀏覽器帶session id過來了,就會使用內存中與之對應的session為之服務。


在談論session機制的時候,常常聽到這樣一種誤解“只要關閉瀏覽器,session就消失了”。除非程序通知服務器刪除一個session,否則服務器會一直保留,程序一般都是在用戶做log off的時候發個指令去刪除session。然而瀏覽器從來不會主動在關閉之前通知服務器它將要關閉,因此服務器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分session機制都使用會話cookie來保存session id,而關閉瀏覽器后這個session id就消失了,再次連接服務器時也就無法找到原來的session。如果服務器設置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發出的HTTP請求頭,把原來的session id發送給服務器,則再次打開瀏覽器仍然能夠找到原來的session。
恰恰是由于關閉瀏覽器不會導致session被刪除,迫使服務器為seesion設置了一個失效時間,當距離客戶端上一次使用session的時間超過這個失效時間時,服務器就可以認為客戶端已經停止了活動,才會把session刪除以節省存儲空間。


每個人只需要保存自己的session id,而我需要保存所有人的session id ! 如果訪問我的人多了, 就得由成千上萬,甚至幾十萬個。
后來有個叫Memcached的給我支了招: 把session id 集中存儲到一個地方, 所有的機器都來訪問這個地方的數據, 這樣一來,就不用復制了, 但是增加了單點失敗的可能性, 要是那個負責session 的機器掛了, 所有人都得重新登錄一遍, 估計得被人罵死。

這幾天的晚上我一直在思考, 我為什么要保存這可惡的session呢, 只讓每個客戶端去保存該多好?

可是如果我不保存這些session id , 我怎么驗證客戶端發給我的session id 的確是我生成的呢? 如果我不去驗證,我都不知道他們是不是合法登錄的用戶, 那些不懷好意的家伙們就可以偽造session id , 為所欲為了。

嗯,對了,關鍵點就是驗證 !

比如說, 小F已經登錄了系統, 我給他發一個令牌(token), 里邊包含了小F的 user id, 下一次小F 再次通過Http 請求訪問我的時候, 把這個token 通過Http header 帶過來不就可以了。

這樣一來, 我就不保存session id 了, 我只是生成token , 然后驗證token , 我用我的CPU計算時間獲取了我的session 存儲空間 !

解除了session id這個負擔, 可以說是無事一身輕, 我的機器集群現在可以輕松地做水平擴展, 用戶訪問量增大, 直接加機器就行。 這種無狀態的感覺實在是太好了!

那是不是session就沒有用了呢,web是不是可以不用session?

當然可以,但是 web 端如果不使用 session,就會失去一些 Spring Security 默認提供的特性,例如登陸成功后跳轉到登陸前的頁面這個功能就是使用 HttpSessionRequestCache 來存儲 SavedRequest 實現的(UsernamePasswordAuthenticationFilter.successHandler),還有如 RedirectAttributes 也需要 session,不使用 session 的時候,還需要這些功能的話,就得自己實現相關功能,把相關數據保存到 Redis,Cookie 等了。需要權衡有沒有必要那么純粹的不使用 session。

Token 怎么驗證和存儲?

上面只介紹了身份認證時使用 token,沒有介紹怎么驗證 token 是否有效,怎么獲取 token 對應的用戶信息。一種方案就是使用 Redis,token 為 key,用戶信息為 value,并給 key 設置過期時間。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。