<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文帶你徹底搞懂Cookie、Session和Token

          共 10392字,需瀏覽 21分鐘

           ·

          2021-08-23 14:15

          在學(xué)習(xí)CookieSessionToken之前,我們先了解下HTTP的無狀態(tài)協(xié)議。

          1、HTTP的無狀態(tài)協(xié)議

          HTTP無狀態(tài)協(xié)議是指該協(xié)議對事件的處理過程沒有記憶能力,當(dāng)后續(xù)的步驟需要上一步的信息時,則需要重傳,即需要攜帶上一次的信息。

          因此,對于存在依賴性的訪問請求,則下一次的傳遞需要攜帶上一次傳遞的信息,依次不斷的疊加,會導(dǎo)致傳輸?shù)男畔⒘繒絹碓酱?,服?wù)器響應(yīng)較慢。

          HTTP無狀態(tài)訪問

          在90年代,瀏覽器剛出現(xiàn)的時候,它的作用也僅僅是瀏覽一些文本而已,彼此之間不存在依賴關(guān)系(在后面的學(xué)習(xí)中,我們把這種依賴關(guān)系理解為會話)。因此,服務(wù)器不需要做任何的記錄,瀏覽器請求什么,服務(wù)器就返回什么,彼此之間清清楚楚,不存在任何的愛恨情仇,雙方的關(guān)系非常的融洽。

          隨著技術(shù)的發(fā)展,特別是當(dāng)客戶端與服務(wù)器進(jìn)行動態(tài)交互的Web應(yīng)用程序出現(xiàn)之后,HTTP的無狀態(tài)特征嚴(yán)重影響了這類Web應(yīng)用程序,Web應(yīng)用的交互是雙向,需要承前啟后的,總不能每次都失憶。

          就像夏洛特?zé)乐?,夏洛和大爺?shù)膶υ挘?/p>

          夏洛:大爺,樓上322住的是馬冬梅家嗎?
          大爺:馬冬什么?
          夏洛:馬冬梅。
          大爺:什么冬梅啊?
          夏洛:馬冬梅啊。
          大爺:馬什么梅???
          夏洛:……行,大爺,您先涼快吧。

          如簡單的購物車程序也要知道用戶到底在之前選擇了什么商品,總不能所有用戶都使用一個購物車吧,所以需要把每個用戶都區(qū)分開,服務(wù)器需要記錄每個用戶的會話,又因為HTTP是無狀態(tài)的,那么就要想辦法為每個用戶保持一個會話。

          因此市面上出現(xiàn)了兩種保持HTTP連接狀態(tài)的技術(shù):CookieSession

          Cookie是客戶端保持HTTP會話狀態(tài)的技術(shù),而Session是服務(wù)端保持HTTP會話狀態(tài)的技術(shù)。通常情況下,這兩種技術(shù)是結(jié)合使用的。

          下面,我們將分別學(xué)習(xí)Cookie、Session,并針對它們的不足,學(xué)習(xí)Token的原理與使用。

          2、Cookie

          在學(xué)習(xí)Cookie之前,我們先考慮以下問題:

          (1)什么是Cookie,Cookie的作用是什么?

          (2)Cookie的工作機制是什么?

          (3)Cookie的基本屬性有哪些?

          針對上面的問題,我們一一來做解答。

          2.1 Cookie的原理及工作機制

          按照官方的定義:

          Cookie是保存在客戶端瀏覽器中的文本文件(key-value形式),這個文件與訪問的特定的Web頁面(文檔)關(guān)聯(lián)在一起,并且保存在本地的客戶端中,Cookie 最根本的用途是幫助 Web 站點保存有關(guān)訪問者的信息。

          舉個例子,當(dāng)客戶端瀏覽器訪問服務(wù)端時,服務(wù)端會記錄每個用戶的訪問信息并以Cookie文件的形式保存在客戶端,當(dāng)用戶再次訪問服務(wù)端的特定頁面時,服務(wù)端會首先檢查客戶端攜帶的Cookie中的用戶身份信息,從而保持了會話的進(jìn)行。

          什么意思呢,我們舉個生活中的例子:

          當(dāng)我們?nèi)ャy行辦理儲蓄業(yè)務(wù)時,柜員第一次給我們辦了張銀行卡,里面存放了身份證、密碼、手機等個人信息。當(dāng)我們下次再來這個銀行時,銀行機器能識別這種卡,從而能夠直接辦理業(yè)務(wù)。

          那么問題來了,Cookie到底是如何起作用的呢?

          事實上,當(dāng)用戶每次訪問服務(wù)器時,Web應(yīng)用程序都可以讀取Cookie包含的信息,當(dāng)用戶再次訪問該頁面時,瀏覽器就會在本地硬盤上查找與該URL相關(guān)的Cookie,如果該 Cookie 存在(Cookie在不過期的情況下),瀏覽器就將它添加到request headerCookie字段中,與http請求一起發(fā)送到該站點。

          我們以登錄為例:

          • 實現(xiàn)登陸我們就必須需要cookie, 使用 cookie 來保存用戶的信息。

          • 在請求某個域的時候,http 會自動將這個域的 Cookie 放到請求頭當(dāng)中。所以我們只需要在登陸用戶成功后,將必要的信息通過設(shè)置 Set-Cookie 這個響應(yīng)頭返回給客戶端。

          • 瀏覽器會自動將該頭的信息存儲到當(dāng)前域名下的 Cookie 中,當(dāng)下次用戶請求的時候,http 協(xié)議會自動將該 cookie 帶上。我們就可以在每次的請求的請求頭當(dāng)中拿到該 Cookie, 然后去判斷用戶是否登陸,進(jìn)而根據(jù)用戶是否登陸進(jìn)行相應(yīng)的處理。

          NOTE:

          Cookie被添加到 request header 中是「瀏覽器的行為」,存儲在cookie的數(shù)據(jù)「每次」都會被瀏覽器「自動」放在http請求中。Cookie過多的信息會增加網(wǎng)絡(luò)流量,因此,我們必須考慮什么樣的數(shù)據(jù)才能放入到Cookie中,我們用的最多的是身份驗證信息。

          因此,當(dāng)用戶第一次訪問并登陸一個網(wǎng)站的時候,Cookie的設(shè)置以及發(fā)送會經(jīng)歷以下4個步驟:

          (1)客戶端發(fā)送一個請求數(shù)據(jù)

          (2)服務(wù)器發(fā)送一個HttpResponse響應(yīng)到客戶端,該響應(yīng)包含Set-Cookie頭部

          (3)客戶端保存Cookie,之后向服務(wù)器發(fā)送請求時,HttpRequest請求中會包含一個Cookie的頭部

          (4)服務(wù)器返回響應(yīng)數(shù)據(jù)

          攜帶Cookie訪問

          2.2 Cookie的組成

          登錄為例,一般來說我們不會在用戶登陸后將用戶的用戶名和密碼設(shè)置到 Cookie 中,從而直接在請求頭拿到用戶名和密碼,然后去判斷用戶是否登陸,這些信息過于敏感,暴露出來十分危險。

          通常情況下,正確的做法應(yīng)該是不管用戶是否登錄,都應(yīng)該通過 Cookie 給用戶返回一個標(biāo)志(通常稱為session_id或者token 等,在下面的部分具體展開),并需要設(shè)置其過期時間、httpOnly、path等。每次用戶請求時,都根據(jù)這個標(biāo)志在服務(wù)端去取根據(jù)這個標(biāo)志存在服務(wù)端的用戶的信息。

          因此,Cookie一般由以下幾部分構(gòu)成

          (1)Name/Value:

          該屬性是設(shè)置Cookie的名稱及相對應(yīng)的值,該值通常是保留在Cookie中的用戶信息。對于認(rèn)證Cookie,Value值包括Web服務(wù)器所提供的訪問令牌(繼續(xù)往下看,下面內(nèi)容會學(xué)習(xí)令牌)。

          (2)Expires屬性:

          該屬性是設(shè)置Cookie的生存周期。

          • 在默認(rèn)情況下,Cookie是臨時存在的。

          • 當(dāng)一個瀏覽器窗口打開時,可以設(shè)置Cookie,只要該瀏覽器窗口沒有關(guān)閉,Cookie就一直有效,而一旦瀏覽器窗口關(guān)閉后,Cookie也就隨之消失。

          • 如果想要cookie在瀏覽器窗口之后還能繼續(xù)使用,就需要為Cookie設(shè)置一個生存期。所謂生存期也就是Cookie的終止日期,在這個終止日期到達(dá)之前,瀏覽器都可以讀取該Cookie。一旦終止日期到達(dá)之后,該cookie將會從cookie文件中刪除。

          (3)Path屬性:

          定義了Web站點上可以訪問該Cookie的目錄。比如,設(shè)置為"/"表示允許當(dāng)前域名下的所有路徑都可以使用該Cookie。

          (4)Domain屬性:

          指定了可以訪問該 Cookie 的 Web 站點,默認(rèn)為當(dāng)前域。

          如當(dāng)前域是www.simon.item,那么它的子域www.simon.item.count共享父域的Cookie,對于不同的域或者平行域則無法共享該Cookie。

          (5)Secure屬性:

          secure是 cookie 的安全標(biāo)志,指定是否使用HTTPS安全協(xié)議發(fā)送Cookie。

          (6)HTTPOnly 屬性 :

          用于防止客戶端腳本通過document.cookie屬性訪問Cookie,有助于保護(hù)Cookie不被跨站腳本攻擊竊取或篡改。

          綜上所述,服務(wù)器通過發(fā)送一個名為 Set-Cookie(Cookie是一個對象,需要自己new出來) 的HTTP頭來創(chuàng)建一個cookie,并作為 Response Headers 的一部分。每個Set-Cookie 表示一個 Cookie(如果有多個Cookie,需寫多個Set-Cookie),每個屬性也是以名/值對的形式(除了secure),屬性間以分號加空格隔開。格式如下:

          Set-Cookie: name1=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
          Set-Cookie: name2=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
          Set-Cookie: name3=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
          ......

          除了在服務(wù)器端設(shè)置,還可以在客戶端設(shè)置Cookie

          document.cookie = "test1=myCookie1;"
          document.cookie = "test2=myCookie2; domain=.google.com.hk; path=/webhp"
          document.cookie = "test3=myCookie3; domain=.google.com.hk; expires=Sat, 08 AUG 2021 16:00:00 GMT; secure"
          document.cookie = "test4=myCookie4; domain=.google.com.hk; max-age=10800;"

          NOTE:只有name/value可以被發(fā)送至服務(wù)端,其余的參數(shù)僅僅是服務(wù)端給客戶端的指示或者客戶端自身的約束。

          由于Cookie的出現(xiàn)可以解決HTTP的無狀態(tài),維持會話的正常進(jìn)行,我們使用Cookie的應(yīng)用場景通常有以下幾種:

          (1)購物車(網(wǎng)購)

          (2)自動登錄(登錄賬號時的自動登錄)

          (3)精準(zhǔn)廣告

          平常瀏覽網(wǎng)頁時有時會推出商品剛好是你最近瀏覽過,買過的類似東西,這些是通過cookie記錄的。

          雖然Cookie有很多優(yōu)點,其缺點也很明顯。

          (1)每個域的Cookie總數(shù)是有限的,不同瀏覽器之間各有不同

          如Firefox限制每個域最多50個cookie,IE限制50個,Chrome對于每個域的Cookie數(shù)量沒有規(guī)定

          (2)Cookie大小限制

          大多數(shù)瀏覽器限制Cookie的大小為4KB

          (3)安全性

          Cookie文件中可能含有涉密信息,可能會導(dǎo)致信息泄露。

          由于Cookie存儲信息的大小不僅有限制,而且還存在信息安全問題,因此,必須想辦法把一些具體的信息存儲到服務(wù)端上。因此,Session的出現(xiàn)可以解決這個問題。

          3、Session

          Session在計算機中被稱為會話控制。

          Session對象可以存儲特定用戶會話所需的屬性配置信息,它通過給不同的用戶發(fā)送session_id并放在Cookie中,然后具體的數(shù)據(jù)則是保存在session中。

          如果用戶已經(jīng)登錄,則服務(wù)器會在Cookie中保存一個session_id,下次再次請求的時候,會把該session_id攜帶上來,服務(wù)器根據(jù)session_id在session庫中獲取用戶的session數(shù)據(jù)。就能知道該用戶到底是誰,以及之前保存的一些狀態(tài)信息,從而保持會話連接的狀態(tài)。

          圖解如下:

          Cookie+Session

          Session流程對應(yīng)的后端代碼如下:

          package xdp.gacl.session;

          import java.io.IOException;
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          import javax.servlet.http.HttpSession;

          public class SessionDemo1 extends HttpServlet {

              public void doGet(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException 
          {

                  response.setCharacterEncoding("UTF=8");
                  response.setContentType("text/html;charset=UTF-8");
                  //使用request對象的getSession()獲取session,如果session不存在則創(chuàng)建一個
                  HttpSession session = request.getSession();
                  //將數(shù)據(jù)存儲到session中
                  session.setAttribute("data""小郎同學(xué)");
                  //獲取session的Id
                  String sessionId = session.getId();
                  //判斷session是不是新創(chuàng)建的
                  if (session.isNew()) {
                      response.getWriter().print("session創(chuàng)建成功,session的id是:"+sessionId);
                  }else {
                      response.getWriter().print("服務(wù)器已經(jīng)存在該session了,session的id是:"+sessionId);
                  }
              }

              public void doPost(HttpServletRequest request, HttpServletResponse response)
                      throws ServletException, IOException 
          {
                  doGet(request, response);
              }
          }

          隨著訪問服務(wù)器的用戶數(shù)量的增多,服務(wù)器上保存的Session也日益增多,這對服務(wù)器來說是個巨大的開銷,對于單個服務(wù)器的Web應(yīng)用匯總,大量的Session會占用比較多的內(nèi)存。

          不僅如此,在分布式系統(tǒng)中,由于負(fù)載均衡對請求轉(zhuǎn)發(fā),這樣就有可能導(dǎo)致同一個用戶的請求分發(fā)到不同的服務(wù)器上,會出現(xiàn)不能獲取不到Session的情況。

          Session不一致原理圖

          Session不一致原理圖

          解決Session不一致的情況通常有三種方法。

          1、反向代理hash一致性

          這類方法是使用Nginx的負(fù)載均衡算法其中的hash_ip算法將ip固定到某一臺服務(wù)器上,這樣就不會出現(xiàn)session共享問題,因為同一個ip訪問下,永遠(yuǎn)是同一個服務(wù)器。

          反向代理hash一致性

          但是這樣的做法也是不保險的,當(dāng)綁定的機器掛了,請求還是會被分發(fā)到別的機器上去。

          因此,可以對多個服務(wù)器間進(jìn)行Session復(fù)制,這樣就可以保障每個服務(wù)器上都包好全部請求的session

          2、Session復(fù)制

          Session復(fù)制

          多個服務(wù)器間進(jìn)行Session復(fù)制非常占用內(nèi)網(wǎng)的帶寬,每個服務(wù)器都有相同的Session不僅導(dǎo)致服務(wù)器的空間利用降低,而且受內(nèi)存的限制,無法水平擴(kuò)展。

          既然每個服務(wù)器都包含相同的Session,我們可以把Session統(tǒng)一存儲管理。

          3、共享Session服務(wù)器

          該方法是把Session集中存儲一個服務(wù)器上,Session服務(wù)器是將有狀態(tài)的Session信息與無狀態(tài)的應(yīng)用服務(wù)器相分離,所有的請求都來訪問這個session服務(wù)器。

          共享Session服務(wù)器

          這種方法雖然不再需要復(fù)制,但是卻增加了單點失敗的可能性,如果負(fù)責(zé)Session的機器掛了,那么保存所有用戶信息的Session將會丟失。有沒有一種辦法使得服務(wù)端存儲這些session呢?

          在這個基礎(chǔ)上,Token就出現(xiàn)了。

          4、Token

          通常意義上的token是把session中的內(nèi)容都放到token中(可以明文形式或者用對稱加密算法加密(加密密鑰放在服務(wù)器端), 然后再把這些內(nèi)容做hash簽名(密鑰在服務(wù)器),把內(nèi)容和其簽名拼接成一個字符串(這個就是token) 發(fā)送給客戶端。

          客戶端后續(xù)請求都帶上這個token,服務(wù)器首先校驗token是否被篡改(根據(jù)hash簽名校驗),如果沒被篡改而且token 也沒過期,就把token中的用戶信息(可能還有權(quán)限信息等等)拿出來,直接使用,不需要像session一樣去查詢具體用戶信息。

          通常情況下,基于Token的身份驗證的過程如下:

          (1)用戶通過用戶名和密碼發(fā)送請求。

          (2)程序驗證。

          (3)程序返回一個簽名的token 給客戶端。

          (4)客戶端儲存token,并且每次用于每次發(fā)送請求。

          (5)服務(wù)端驗證token并返回數(shù)據(jù)。

          使用token訪問

          Token具有以下的優(yōu)勢

          (1)無狀態(tài)、可擴(kuò)展

          在客戶端存儲的token是無狀態(tài)的,并且能夠被擴(kuò)展。基于這種無狀態(tài)和不存儲Session信息,負(fù)載負(fù)載均衡器能夠?qū)⒂脩粜畔囊粋€服務(wù)傳到其他服務(wù)器上。

          如果我們將已驗證的用戶的信息保存在Session中,則每次請求都需要用戶向已驗證的服務(wù)器發(fā)送驗證信息(稱為Session親和性)。用戶量大時,可能會造成一些擁堵。

          但是不要著急。使用tokens之后這些問題都迎刃而解,因為服務(wù)端使用token可以使用秘鑰找到用戶的信息。

          (2)安全性

          請求中發(fā)送token而不再是發(fā)送cookie能夠防止CSRF(跨站請求偽造)。即使在客戶端使用cookie存儲token,cookie也僅僅是一個存儲機制而不是用于認(rèn)證。不將信息存儲在Session中,讓我們少了對session操作。

          token是有時效的,一段時間之后用戶需要重新驗證。我們也不一定需要等到token自動失效,token有撤回的操作,通過token revocataion可以使一個特定的token或是一組有相同認(rèn)證的token無效。

          • 可擴(kuò)展性

          使用token時,可以提供可選的權(quán)限給第三方應(yīng)用程序。當(dāng)用戶想讓另一個應(yīng)用程序訪問它們的數(shù)據(jù),我們可以通過建立自己的API,得出特殊權(quán)限的tokens。

          如使用微信登錄微博

          • 多平臺跨域

          只要用戶有一個通過了驗證的token,數(shù)據(jù)和資源就能夠在任何域上被請求到。

          總結(jié)

          下面,我們對Cookie、Session和Token做以下總結(jié):

          HTTP請求是無狀態(tài)的,就是說第一次和服務(wù)器連接并登陸成功后,第二次請求服務(wù)器仍然不知道當(dāng)前請求的用戶。Cookie出現(xiàn)就是解決了這個問題,第一次登陸后服務(wù)器返回一些數(shù)據(jù)(cookie)給瀏覽器,然后瀏覽器保存在本地,當(dāng)用戶第二次返回請求的時候,就會把上次請求存儲的cookie數(shù)據(jù)自動攜帶給服務(wù)器。

          如果關(guān)閉瀏覽器Cookie失效(Cookie就是保存在內(nèi)存中) 

          如果關(guān)閉瀏覽器Cookie不失效(Cookie保存在磁盤中)

          Session和Cookie的作用有點類似,都是為了存儲用戶相關(guān)的信息。

          不同的是,Cookie是存儲在本地瀏覽器,而Session存儲在服務(wù)器。存儲在服務(wù)器的數(shù)據(jù)會更加的安全,不容易被竊取。但存儲在服務(wù)器也有一定的弊端,就是會占用服務(wù)器的資源。

          存儲在服務(wù)端

          • 通過cookie存儲一個session_id,然后具體的數(shù)據(jù)則是保存在session中。
          • 如果用戶已經(jīng)登錄,則服務(wù)器會在cookie中保存一個session_id,下次再次請求的時候,會把該session_id攜帶上來,服務(wù)器根據(jù)session_id在session庫中獲取用戶的session數(shù)據(jù)。就能知道該用戶到底是誰,以及之前保存的一些狀態(tài)信息。

          1、Cookie與Session的區(qū)別

          cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務(wù)器上。

          cookie不是很安全,別人可以分析存放在本地的cookie并進(jìn)行cookie欺騙考慮到安全應(yīng)當(dāng)使用session。

          session會在一定時間內(nèi)保存在服務(wù)器上。當(dāng)訪問增多,會比較占用你服務(wù)器的性能考慮到減輕服務(wù)器性能方面,應(yīng)當(dāng)使用cookie。

          單個cookie保存的數(shù)據(jù)不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。因此使用cookie只能存儲一些小量的數(shù)據(jù)。

          所以開發(fā)人員的通常做法是:

          將登陸信息等重要信息存放為Session 其他信息如果需要保留,可以放在Cookie中

          2、Token和Session的區(qū)別

          共同點:

          都是保存了用戶身份信息,都有過期時間。

          不同點:

          session翻譯為會話,token翻譯為令牌。

          session是空間換時間,token是時間換空間

          session和session_id:服務(wù)器會保存一份,可能保存到緩存/數(shù)據(jù)庫/文件。

          token:服務(wù)器不需要記錄任何東西,每次都是一個無狀態(tài)的請求,每次都是通過解密來驗證是否合法。token 只是一個 key,不存放實際的數(shù)據(jù),與這個 token 相關(guān)的數(shù)據(jù)還是存放在服務(wù)器上,例如 Session,Redis 等分布式緩存里,用 token 去請求對應(yīng)的數(shù)據(jù)。

          session_id:一般是隨機字符串,要到服務(wù)器檢索id的有效性。出現(xiàn)請求:服務(wù)器重啟內(nèi)存中的session沒了,數(shù)據(jù)庫服務(wù)器掛了。

          token 和 cookie 本質(zhì)上沒啥區(qū)別,只不過 token 只是一個字符串,訪問的時候可以放在 url 的參數(shù),header 里等,不像 cookie 那么重量級,而且移動端訪問的時候 token 更方便,僅此而已。

          巨人的肩膀

          [1]https://segmentfault.com/a/1190000006156098
          [2]https://www.cnblogs.com/moyand/p/9047978.html
          [3]https://blog.csdn.net/qq_43542074/article/details/100395011
          [4]https://baike.baidu.com/item/HTTP%E6%97%A0%E7%8A%B6%E6%80%81%E5%8D%8F%E8%AE%AE/5808645?fr=aladdin

          往期推薦

          機械碩士轉(zhuǎn)計算機,我是怎么做的?

          Typora+PicGo+Gitee搭建博客寫作環(huán)境

          沒有Linux服務(wù)器,該如何學(xué)習(xí)Linux呢?

          大廠的產(chǎn)品研發(fā)流程,你知道么?

          上海有哪些互聯(lián)網(wǎng),你都知道么?



          瀏覽 113
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久久久国产精品嫩草影院 | 黄色无码视频在线客服 | 欧日成人网站 | 欧美精品久久 | 日本精品一区二区视频 |