http是無狀態的,一次請求結束,連線斷開,下次伺服器再收到請求,它就不知道這個請求是哪個使用者發過來的。當然它知道是哪個客戶端位址發過來的,但是對於我們的應用來說,我們是靠使用者來管理,而不是靠客戶端。所以對我們的應用而言,它是需要有狀態管理的,以便服務端能夠準確的知道http請求是哪個使用者發起的,從而判斷他是否有許可權繼續這個請求。這個過程就是常說的會話管理。它也可以簡單理解為乙個使用者從登入到退出應用的一段期間。本文總結了3種常見的實現web應用會話管理的方式:
1)基於server端session的管理方式
2)cookie-base的管理方式
3)token-base的管理方式
在早期web應用中,通常使用服務端session來管理使用者的會話。快速了解服務端session:
1) 服務端session是使用者第一次訪問應用時,伺服器就會建立的物件,代表使用者的一次會話過程,可以用來存放資料。伺服器為每乙個session都分配乙個唯一的sessionid,以保證每個使用者都有乙個不同的session物件。
2)伺服器在建立完session後,會把sessionid通過cookie返回給使用者所在的瀏覽器,這樣當使用者第二次及以後向伺服器傳送請求的時候,就會通過cookie把sessionid傳回給伺服器,以便伺服器能夠根據sessionid找到與該使用者對應的session物件。
3)session通常有失效時間的設定,比如2個小時。當失效時間到,伺服器會銷毀之前的session,並建立新的session返回給使用者。但是只要使用者在失效時間內,有傳送新的請求給伺服器,通常伺服器都會把他對應的session的失效時間根據當前的請求時間再延長2個小時。
4)session在一開始並不具備會話管理的作用。它只有在使用者登入認證成功之後,並且往sesssion物件裡面放入了使用者登入成功的憑證,才能用來管理會話。管理會話的邏輯也很簡單,只要拿到使用者的session物件,看它裡面有沒有登入成功的憑證,就能判斷這個使用者是否已經登入。當使用者主動退出的時候,會把它的session物件裡的登入憑證清掉。所以在使用者登入前或退出後或者session物件失效時,肯定都是拿不到需要的登入憑證的。
以上過程可簡單使用流程圖描述如下:?
主流的web開發平台(j**a,.net,php)都原生支援這種會話管理的方式,而且開發起來很簡單,相信大部分後端開發人員在入門的時候都了解並使用過它。它還有乙個比較大的優點就是安全性好,因為在瀏覽器端與伺服器端保持會話狀態的媒介始終只是乙個sessionid串,只要這個串夠隨機,攻擊者就不能輕易冒充他人的sessionid進行操作;除非通過csrf或http劫持的方式,才有可能冒充別人進行操作;即使冒充成功,也必須被冒充的使用者session裡面包含有效的登入憑證才行。但是在真正決定用它管理會話之前,也得根據自己的應用情況考慮以下幾個問題:
1)這種方式將會話資訊儲存在web伺服器裡面,所以在使用者同時**量比較多時,這些會話資訊會佔據比較多的記憶體;
2)當應用採用集群部署的時候,會遇到多台web伺服器之間如何做session共享的問題。因為session是由單個伺服器建立的,但是處理使用者請求的伺服器不一定是那個建立session的伺服器,這樣他就拿不到之前已經放入到session中的登入憑證之類的資訊了;
3)多個應用要共享session時,除了以上問題,還會遇到跨域問題,因為不同的應用可能部署的主機不一樣,需要在各個應用做好cookie跨域的處理。
針對問題1和問題2,我見過的解決方案是採用redis這種中間伺服器來管理session的增刪改查,一來減輕web伺服器的負擔,二來解決不同web伺服器共享session的問題。針對問題3,由於服務端的session依賴cookie來傳遞sessionid,所以在實際專案中,只要解決各個專案裡面如何實現sessionid的cookie跨域訪問即可,這個是可以實現的,就是比較麻煩,前後端有可能都要做處理。
如果不考慮以上三個問題,這種管理方式比較值得使用,尤其是一些小型的web應用。但是一旦應用將來有擴充套件的必要,那就得謹慎對待前面的三個問題。如果真要在專案中使用這種方式,推薦結合單點登入框架如cas一起用,這樣會使應用的擴充套件性更強。
由於前一種方式會增加伺服器的負擔和架構的複雜性,所以後來就有人想出直接把使用者的登入憑證直接存到客戶端的方案,當使用者登入成功之後,把登入憑證寫到cookie裡面,並給cookie設定有效期,後續請求直接驗證存有登入憑證的cookie是否存在以及憑證是否有效,即可判斷使用者的登入狀態。使用它來實現會話管理的整體流程如下:
1)使用者發起登入請求,服務端根據傳入的使用者密碼之類的身份資訊,驗證使用者是否滿足登入條件,如果滿足,就根據使用者資訊建立乙個登入憑證,這個登入憑證簡單來說就是乙個物件,最簡單的形式可以只包含使用者id,憑證建立時間和過期時間三個值。
2)服務端把上一步建立好的登入憑證,先對它做數字簽名,然後再用對稱加密演算法做加密處理,將簽名、加密後的字串,寫入cookie。cookie的名字必須固定(如ticket),因為後面再獲取的時候,還得根據這個名字來獲取cookie值。這一步新增數字簽名的目的是防止登入憑證裡的資訊被篡改,因為一旦資訊被篡改,那麼下一步做簽名驗證的時候肯定會失敗。做加密的目的,是防止cookie被別人擷取的時候,無法輕易讀到其中的使用者資訊。
3)使用者登入後發起後續請求,服務端根據上一步存登入憑證的cookie名字,獲取到相關的cookie值。然後先做解密處理,再做數字簽名的認證,如果這兩步都失敗,說明這個登入憑證非法;如果這兩步成功,接著就可以拿到原始存入的登入憑證了。然後用這個憑證的過期時間和當前時間做對比,判斷憑證是否過期,如果過期,就需要使用者再重新登入;如果未過期,則允許請求繼續。
這種方式最大的優點就是實現了服務端的無狀態化,徹底移除了服務端對會話的管理的邏輯,服務端只需要負責建立和驗證登入cookie即可,無需保持使用者的狀態資訊。對於第一種方式的第二個問題,使用者會話資訊共享的問題,它也能很好解決:因為如果只是同乙個應用做集群部署,由於驗證登入憑證的**都是一樣的,所以不管是哪個伺服器處理使用者請求,總能拿到cookie中的登入憑證來進行驗證;如果是不同的應用,只要每個應用都包含相同的登入邏輯,那麼他們也是能輕易實現會話共享的,不過這種情況下,登入邏輯裡面數字簽名以及加密解密要用到的金鑰檔案或者金鑰串,需要在不同的應用裡面共享,總而言之,就是需要演算法完全保持一致。
這種方式由於把登入憑證直接存放客戶端,並且需要cookie傳來傳去,所以它的缺點也比較明顯:
1)cookie有大小限制,儲存不了太多資料,所以要是登入憑證存的訊息過多,導致加密簽名後的串太長,就會引發別的問題,比如其它業務場景需要cookie的時候,就有可能沒那麼多空間可用了;所以用的時候得謹慎,得觀察實際的登入cookie的大小;比如太長,就要考慮是非是數字簽名的演算法太嚴格,導致簽名後的串太長,那就適當調整簽名邏輯;比如如果一開始用4096位的rsa演算法做數字簽名,可以考慮換成1024、2048位;
2)每次傳送cookie,增加了請求的數量,對訪問效能也有影響;
3)也有跨域問題,畢竟還是要用cookie。
相比起第一種方式,cookie-based方案明顯還是要好一些,目前好多web開發平台或框架都預設使用這種方式來做會話管理,比如php裡面yii框架,這是我們團隊後端目前用的,它用的就是這個方案,以上提到的那些登入邏輯,框架也都已經封裝好了,實際用起來也很簡單;asp.net裡面forms身份認證,也是這個思路,這裡有一篇好文章把它的實現細節都說的很清楚:
前面兩種會話管理方式因為都用到cookie,不適合用在native app裡面:native app不好管理cookie,畢竟它不是瀏覽器。這兩種方案都不適合用來做純api服務的登入認證。要實現api服務的登入認證,就要考慮下面要介紹的第三種會話管理方式。
這種方式從流程和實現上來說,跟cookie-based的方式沒有太多區別,只不過cookie-based裡面寫到cookie裡面的ticket在這種方式下稱為token,這個token在返回給客戶端之後,後續請求都必須通過url引數或者是http header的形式,主動帶上token,這樣服務端接收到請求之後就能直接從http header或者url裡面取到token進行驗證:
這種方式不通過cookie進行token的傳遞,而是每次請求的時候,主動把token加到http header裡面或者url後面,所以即使在native app裡面也能使用它來呼叫我們通過web發布的api介面。app裡面還要做兩件事情:
1)有效儲存token,得保證每次調介面的時候都能從同乙個位置拿到同乙個token;
2)每次調介面的的**裡都得把token加到header或者介面位址裡面。
看起來麻煩,其實也不麻煩,這兩件事情,對於app來說,很容易做到,只要對介面呼叫的模組稍加封裝即可。
這種方式同樣適用於網頁應用,token可以存於localstorage或者sessionstorage裡面,然後每發ajax請求的時候,都把token拿出來放到ajax請求的header裡即可。不過如果是非介面的請求,比如直接通過點選鏈結請求乙個頁面這種,是無法自動帶上token的。所以這種方式也僅限於走純介面的web應用。
Web會話管理
基於token的管理 重新整理安全問題 web應用通常使用的是http請求,但是http是無狀態的,一次請求結束,連線就會自動斷開,伺服器只能知道每個請求的 位址,可是這對會話的管理毫無意義。根本無法對使用者進行認證和許可權控制。於是,就有了相應的方案來解決這問題。常用的方法有三個 在早期的web應...
三種會話管理方式
1.http是無狀態的協議 http協議不要求客戶端 瀏覽器 在每次請求中標明身份,客戶端和伺服器間沒有乙個持久連線來用於多個頁面間的訪問。客戶端發乙個請求,伺服器給乙個回覆。2.三種會話管理方式 第一種 session 客 戶 端 http過程 處理動作 服 務 器 1.第一次請求 伺服器建立乙個...
web會話管理基礎
會話要解決的問題 每個使用者在使用瀏覽器與伺服器進行會話的過程中,不可避免各自會產生一些資料,程式要想辦法為每乙個使用者儲存這些資料,這就是會話要解決的問題。解決會話問題的兩種技術 cookie cookie是客戶端技術,程式把每乙個使用者的資料以cookie的形式寫給使用者各自的瀏覽器,當使用者使...