分類
發燒車訊

怎樣實現登錄?| Cookie or JWT_貨運

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

先問小夥伴們一個問題,登錄難嗎?“登錄有什麼難得?輸入用戶名和密碼,後台檢索出來,校驗一下不就行了。”凡是這樣回答的小夥伴,你明顯就是產品思維,登錄看似簡單,用戶名和密碼,後台校驗一下,完事了。但是,登錄這個過程涵蓋的知識點是非常多的,絕不是檢索數據,校驗一下這麼簡單的事。

那麼登錄都要哪些實現方式呢?i最傳統的就要是Cookie-Session這種方式了,最早的登錄方式都是這樣實現的。但是隨着手機端、H5端的興起,前後端分離的模式越來越流行,基於Cookie-Session這種登錄方式不是很方便,漸漸的JTW開始流行,現在大部分項目的登錄方式都是基於JWT的了。那麼Cookie和JWT都是怎樣實現登錄的呢?這兩種方式有什麼區別呢?我們在做登錄的x時候該怎麼選擇呢?咱們先看看這兩種方式的原理。

Cookie方式

因為Http協議是無狀態的,我們後台的服務(如Tomcat)在接收到前端發送過來的Http請求時,是區分不出哪個請求是誰發出的,這和我們的登錄功能是相違背的,登錄的功能就是要區分每一個請求是由哪個用戶發出的,這就變成了有狀態,那怎麼辦呢?Cookie應運而生,Cookie是存儲在瀏覽器端的,在Cookie中存儲的內容是鍵值對,也就是name-value。瀏覽器在向後台發送請求的時候,會把Cookie放在請求頭中,傳送給後台的服務,後台的服務會從請求頭中取到Cookie,再從Cookie中取出鍵值對中jsessionid對應的值。這個jsessionid的值就是你這次會話的id,對應着服務端的一個session。

好了,到這裏session這個概念出來了,session是什麼呢?session是存儲在服務端的,每一個會話對應服務中的一個session。咱們可以把session理解為一個Map,它的key存儲的session的id,value存儲的東西就隨便了,我們在寫程序時想存啥就存啥。它的key存儲的值就是Cookie中存儲的jsessionid的值,這樣,瀏覽器發送請求到後台服務,後台才能根據Cookie中的jsessionid取到對應的session,再從session中取到之前存儲的狀態,如存儲在session中的登錄狀態、用戶id等。Cookie-Session機制是通用的,所有的瀏覽器都支持Cookie,就連最低端的IE都支持,你說他普遍不普遍。Session是後端容器必須支持的,如Tomcat,還有像其他的如Resin、jetty等。這些對開發人員都是透明的,無需過多關注。

Cookie-Session的由來給大家說完了,我們看看基於Cookie這種方式的登錄流程,

  • 用戶在瀏覽器輸入用戶名、密碼,點擊登錄,發送請求到後台服務;
  • 後台服務校驗用戶名、密碼,將登錄狀態狀態和用戶id存儲在session中;
  • 將session的id存儲在Cookie中,通過響應頭返回到瀏覽器;
  • 當用戶點擊其他功能時,向後台發送的請求中會自動帶上Cookie;
  • 後台通過Cookie中的jsessionid找到對應的session,開發人員可從session中取出當前會話的登錄狀態和用戶id。

基於Cookie-Session機制的登錄實現方式的整體流程就是這個樣子。看上去很完美,但還是存在不少問題的,我們來看看這些問題。

分佈式會話

上面的示例,我們的後台服務只有一個,一個服務往往很難支撐服務,為了保障可靠性,最少都是部署兩個後台服務。但是當部署多個後台服務時,我們的session就會出現問題,看看下面的圖,

  • 假如用戶登錄的請求,分配到了後台服務1,後台服務1的session存了用戶的登錄狀態和用戶id。
  • 用戶在點擊其他功能時,請求分配到了後台服務2,可是後台服務2的session並沒有存儲登錄狀態和用戶id。

我們怎麼解決這個問題呢?其實也很簡單,第一,session集中管理,比如使用Redis;第二,所有的後台服務在獲取session時,統一從Redis中獲取。如下所示,

我們可以使用中間件Spring-Session和Redis就可以解決這個問題。

CORS

使用Cookie實現登錄的另外一個問題就是跨域,現在往往都採用前後端分離的方式進行開發,在開發的過程中,前端和後端通常不在一個域下,由於瀏覽器的同源策略,Cookie不能傳入到後端。至於同源策略,不明白的小夥伴可以問一下度娘,這裏不過多介紹了。要解決這個問題,在前端、後端都要進行設置,在我的另一篇文章《前後端分離|關於登錄狀態那些事》中有詳細的介紹。總體歸納為:

  • 後端設置CORS允許跨域的域名,並且withCredentials設置為true;
  • 前端在向後端發送請求時,也需要設置withCredentials = true;

這樣,我們的Cookie就可以實現跨域了。不進行這些設置,Cookie跨域是不可能的,同源策略保證了我們Cookie的安全。

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

CSRF

CSRF,這個CORS是不一樣的,長的比較像,也比較容易混。CSRF往往和系統的安全扯上聯繫,也是等保測試中比較重要的測試內容,它也是和Cookie有關的,大體的流程是這樣的,

  • 用戶登錄了A網站,並沒有退出;
  • 此時,用戶又訪問了B網站;
  • 在B網站有個隱藏的請求,請求了A網站的一個重要的接口,比如:轉賬、支付等。
  • 在請求A網站的同時,帶上了A網站的Cookie,所以一些危險的操作就成功了。

關於CSRF的攻防,在我前面的文章《CSRF的原理與防禦 | 你想不想來一次CSRF攻擊?》中有詳細的介紹。總之,使用Cookie實現登錄是需要重點防範一下CSRF攻擊的。

JWT方式

近年來,由於手機端的興起,前後端分離開發方式的流行,JWT這種登錄的實現方式悄然興起,那麼什麼是JWT呢?JWT是英文JSON Web Token的縮寫,它由3部分組成,

  • header,一般情況下存儲兩個信息,1類型,一般都是JWT;2加密算法,比如:HMAC、RSA等;
  • payload,這裏就存儲登錄的相關信息了,比如:登錄狀態、用戶id、過期時間等。
  • signature,簽名,這個是將header、payload和密鑰的信息做一次加密,後台在接收到JWT的時候,一定要驗簽,謹防JWT的偽造。

下面咱們看看JWT的登錄實現,

我們看到整體的流程和Cookie的實現方式是一樣的,只不過是沒有用到Cookie、Session。那麼它與Cookie-Session的區別是什麼呢?

  • 登錄狀態、用戶id並沒有存儲到session,而是存在JWT的payload里,返回給了前端。
  • 在前端JWT不會自動存儲到Cookie中,前端開發人員要處理JWT的存儲問題,比如LocalStorage
  • 再次發起請求,JWT不會自動放到請求頭中,需前端同學手動設置
  • 後端從請求頭中取出JWT,驗簽通過後,拿到登錄狀態、用戶id,不是從session中取

相比Cookie的方式,JWT的方式需要更多的開發工作量。那麼其他的問題存在嗎?我們一個一個看。

分佈式會話

我們後台部署多個服務,會有分佈式會話的問題嗎?

無論請求被分配到哪一個後台服務中,登錄狀態和用戶id都是從JWT中取出來的,不會出現分佈式會話的問題。我們在後台部署集群的時候,根本不用care這個問題。

CORS

Cookie的跨域受到同源策略的保護,不經過特殊的設置,是不能夠跨域的。那麼JWT呢?JWT是前端同學手動在請求頭中設置的,如果向其他的域發送請求要注意,稍不注意,在請求的時候,調用了封裝的公共方法,就會把JWT發送給其他域的後台,前端的小夥伴要打起精神啊。

CSRF

Cookie的方式,B訪問A網站,會把A的Cookie帶上,從而造成了安全隱患。那麼JWT呢?JWT在前端存儲在A網站的域下,B在訪問A網站時,是拿不到A網站的JWT的,那麼也不可能在請求頭中設置JWT,A網站的後台拿不到JWT,也不會做其他操作。所以,JWT可以很好的防止CSRF攻擊。

總結

通過前面我們對Cookie和JWT的分析,可以總結成如下的表格,

Cookie-Session JWT
工作量 瀏覽器和容器天然支持 需要額外開發,有一定工作量
分佈式會話 需要藉助中間件 無需關心,登錄信息從JWT解出
CORS 不支持跨域、需特殊設置 開發人員設置請求頭,可以跨域
CSRF 需特殊防範 無需防範,第三方拿不到JWT

好了,Cookie和JWT的特點都總結出來了,大家在實現登錄的時候,就各取所需吧。結合自己的項目,選擇適合自己項目的實現方式吧。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式