1. 程式人生 > >淺析權限認證中的有狀態和無狀態

淺析權限認證中的有狀態和無狀態

總結 有一個 eth 返回 alt 配置 客戶端信息 傳遞 主動

前言

我們在設計構建一個系統的時候,權限管理和用戶認證是最基本功能,其中關於用戶認證這塊是一個比較常見的模塊。在已有的方案中,我們最常見的就是保存到 tomcat 中的 session 對象中。隨著微服務的興起,一種新的認證方法又火了起來,那就是JWT,下面我就淺析下自己對兩種認證方式的認識,一些經驗和大家探討。

淺談認證

我對認證的理解就是,當一個設備(客戶端)向一個設備(服務端)發送請求的時候,服務端如何判斷這個客戶端是誰。傳統意義有兩種認證方式:有狀態認證、無狀態認證。有狀態和無狀態最大的區別就是服務端會不會保存客戶端的信息。

有狀態認證

有狀態的認證,以 cookie - session 模型為例,當客戶端第一次請求服務端時候,服務端會返回客戶端一個唯一標識(默認在cookie中),並保存對應的客戶端信息。客戶端接受到唯一標識之後,將標識位保存到本地cookie中,以後的每次請求都攜帶此 cookie ,服務端根據此 cookie 標識可以判斷請求的用戶是誰,然後查到對應用戶的信息,大概示意圖如下:

技術分享圖片

請求認證過程(以tomcat為例):

1、客戶端向服務端發起請求;

2、第一次客戶端發起請求,服務端創建一個 key 為JSESSIONID的值,並寫入到客戶端的cookie中,同時在服務端的Session Manager中創建一個對象,保存這個 JSESSIONID 對應的信息;

3、以後客戶端每次請求,都會根據cookie進行區別,我們可以通過 session.setAttrbutie,session.getAttrbuite 等方法,拓展用戶信息,根據用戶信息做一些業務判斷等;

4、Session Manger 中維護有一個定時器,當 JSESSIONID 對應的信息長時間沒有訪問(默認30分鐘),或者顯性調用 session.invalidate 方法,那麽這個對應的信息將會被刪除。

那麽針對有狀態的認證,我們分析下他的利弊:

優勢

因為客戶端的信息都保存在服務端的 Session Manager 中,如果要將客戶端的認證信息取消,只需要將對應的session 信息刪除即可,及時響應,方便快捷。

劣勢

1、因為服務端保存著客戶端的信息,當用戶量特別多時候,服務端需要特別的內存資源;

2、如果失效時間特別長的情況下,大量資源被占用無法釋放,如果釋放,那麽相當於用戶的註銷登錄;

3、客戶端的信息在服務端中維護,如果服務端為集群的場景下,那麽客戶端信息不共享,必須使用分布式 session 或者其他方案;

4、cookie有同源策略和跨域限制,部分業務場景下cookie並不能傳遞;

5、部分設備本身不支持cookie或者禁用cookie,還有的手機瀏覽器也不支持cookie。

應用實戰

1、如果公司以集群式部署多臺服務,那麽可以采用的策略有:配置負載均衡的路由策略為hash一致算法(不推薦),如果某個機器停機,那麽會重新分配到新機器,又需要重新登錄;session復制方式(不推薦),復雜度過高;分布式 session 方案(強力推薦),目前市場上有 spring-session 的依賴,可以將 session 保存的容器從應用內部抽取到 redis 或者 數據庫中供多個應用使用,實現集中管理,為了保證設備的兼容性,spring-session提供了將認證方式從cookie修改為header,web網站可以保存到 SessionStorage,移動端可以保存到本地緩存中。

2、如果一個公司有多個產品需要共享認證信息,此時需要使用 SSO Server。

無狀態

無狀態的認證,客戶端在提交身份信息,服務端驗證身份後,根據一定的算法生成一個 token 令牌返回給客戶端,之後每次請求服務端,客戶端都需要攜帶此令牌,服務端接受到令牌之後進行校驗,校驗通過後,提取令牌中的信息用來區別用戶,大概的示例圖如下:
技術分享圖片

請求認證過程:

1、執行登錄操作,用戶端發送賬號密碼等信息;

2、服務端校驗賬號密碼是否正確,如果正確,根據對應的用戶信息和服務端秘鑰生成 JWT 令牌,然後通過response.setHeader 返回給客戶端(此處假設生成了一個名為 x-auth-token 的令牌);

3、客戶端在返回成功之後,將Header中的x-auth-token 保存到本地的LocalStorage中;

4、客戶端在以後每次請求服務端時候,都在header中攜帶x-auth-token令牌的值;

5、服務端每接受到請求之後,判斷hader中是否包含x-auth-token,token 是否有效,然後通過 BASE 64 算法 decode,根據解密後的參數,判斷當前 token 是否在有效期,所訪問的接口是否有權限等操作。

優勢

1、因為服務端不保留客戶端的任何信息,每次只需要通過特定的算法進行校驗,節省了大量存儲空間;

2、方便水平擴容,不需要 SSO Server,只要保證新的應用采用同樣的驗證算法,就可以驗證通過並獲得對應信息。

劣勢

當客戶端的token被盜用,或者需要手動封禁某個用戶的時候,沒辦法對此token進行操作,必須等待token失效(如果在服務端維護token和用戶的關系,技術可以實現,但是違背無狀態的設計理念)。

應用實戰

1、生成的 token 中攜帶用戶常用信息,但是不攜帶用戶的敏感信息,比如密碼手機號等等,因為這些信息通過BASE 64 可以解密出來的;

2、要處理服務端主動禁用某個 token ,可以采用黑名單措施,每次請求前判斷當前token是否已經被禁用;

3、token 中的信息除了基本信息外,還應該攜帶比如簽發時間、有效時間、刷新token等字段,用來處理token的續約問題。

總結

在實際的項目中,我們該如何選擇認證模式,是有狀態的認證還是無狀態的認證呢?以前看文章時候,在掘金中看到有人把 JWT 批評的一無是處,就和垃圾一樣。我個人覺得吧技術沒有誰好誰壞,誰舊誰新,也沒有誰該被時代淘汰,存在及合理,我們需要充分理解需求,合理使用技術,只有最合適的技術才是最好的選擇。 下面是我關於技術選型時候的一些個人觀點,希望大家批評指正和交流。

在我的經驗中,目前比較流行的就是互聯網APP中大部分采用 JWT 的認證方式,一些企業內部管理系統則大部分采用 cookie-session 的機制,大量的商業案例下,我個人分析推測的原因可能如下:

1、在互聯網APP產品中,尤其以 to C 模式,用戶量極大,為了用戶體驗,一般會將登錄信息保留特別長時間,某些APP 只要你不卸載,那麽不管幾個月之後登錄,賬戶還是處於登錄狀態。在這種情況下,假如采用 cookie-session 機制,那麽你的用戶信息保存很多個月,用戶量特別大的情況下,會造成大量資源占用和浪費,這種場景采用 JWT 就是相對比較好的方案。

2、企業內部管理系統有以下特點:用戶量較少(最多最多不超過10W人),信息安全要求高(及時踢出客戶端登錄狀態,個人瀏覽器關閉賬號退出登錄),在這樣的場景下占用的內存不會太多,所以基於 cookie-session 這種機制,是比較好的方案,如果企業內部還有其他應用需要集成時候,需要使用 SSO Server 實現。

代碼案例

最近在找工作,如果閑下來有時間的時候會寫兩個項目出來,敬請期待:

1、 spring security + JWT 的驗證案例

2、shiro + spring-session (header替換cookie)的驗證方案

ps:螞蟻5面技術過了,期待hr面試的早點到來,給自己加油。

淺析權限認證中的有狀態和無狀態