Cookie、Session、Token講解

2020-12-16 懶人部落

Cookie

洛:大爺,樓上322住的是馬冬梅家吧?

大爺:馬都什麼?

夏洛:馬冬梅。

大爺:什麼都沒啊?

夏洛:馬冬梅啊。

大爺:馬什麼沒?

夏洛:行,大爺你先涼快著吧。

在了解這三個概念之前我們先要了解HTTP是無狀態的Web伺服器,什麼是無狀態呢?就像上面夏洛特煩惱中經典的一幕對話一樣,一次對話完成後下一次對話完全不知道上一次對話發生了什麼。如果在Web伺服器中只是用來管理靜態文件還好說,對方是誰並不重要,把文件從磁碟中讀取出來發出去即可。但是隨著網絡的不斷發展,比如電商中的購物車只有記住了用戶的身份才能夠執行接下來的一系列動作。所以此時就需要我們無狀態的伺服器記住一些事情。

那麼Web伺服器是如何記住一些事情呢?既然Web伺服器記不住東西,那麼我們就在外部想辦法記住,相當於伺服器給每個客戶端都貼上了一個小紙條。上面記錄了伺服器給我們返回的一些信息。然後伺服器看到這張小紙條就知道我們是誰了。那麼

Cookie

是誰產生的呢?Cookies是由伺服器產生的。接下來我們描述一下

Cookie

產生的過程

瀏覽器第一次訪問服務端時,伺服器此時肯定不知道他的身份,所以創建一個獨特的身份標識數據,格式為key=value,放入到Set-Cookie欄位裡,隨著響應報文發給瀏覽器。瀏覽器看到有Set-Cookie欄位以後就知道這是伺服器給的身份標識,於是就保存起來,下次請求時會自動將此key=value值放入到Cookie欄位中發給服務端。服務端收到請求報文後,發現Cookie欄位中有值,就能根據此值識別用戶的身份然後提供個性化的服務。

接下來我們用代碼演示一下伺服器是如何生成,我們自己搭建一個後臺伺服器,這裡我用的是SpringBoot搭建的,並且寫入SpringMVC的代碼如下。

@RequestMapping("/testCookies")

public String cookies(HttpServletResponse response){

response.addCookie(new Cookie("testUser","xxxx"));

return"cookies";

}

項目啟動以後我們輸入路徑http://localhost:8005/testCookies,然後查看發的請求。可以看到下面那張圖使我們首次訪問伺服器時發送的請求,可以看到伺服器返回的響應中有Set-Cookie欄位。而裡面的key=value值正是我們伺服器中設置的值。

接下來我們再次刷新這個頁面可以看到在請求體中已經設置了Cookie欄位,並且將我們的值也帶過去了。這樣伺服器就能夠根據Cookie中的值記住我們的信息了。

接下來我們換一個請求呢?是不是Cookie也會帶過去呢?接下來我們輸入路徑http://localhost:8005請求。我們可以看到Cookie欄位還是被帶過去了。

那麼瀏覽器的Cookie是存放在哪呢?如果是使用的是Chrome瀏覽器的話,那麼可以按照下面步驟。

在計算機打開Chrome在右上角,一次點擊更多圖標->設置在底部,點擊高級隱私設置和安全性下方,點擊網站設置依次點擊Cookie->查看所有Cookie和網站數據然後可以根據域名進行搜索所管理的Cookie數據。所以是瀏覽器替你管理了Cookie的數據,如果此時你換成了Firefox等其他的瀏覽器,因為Cookie剛才是存儲在Chrome裡面的,所以伺服器又蒙圈了,不知道你是誰,就會給Firefox再次貼上小紙條。

Cookie中的參數設置

說到這裡,應該知道了Cookie就是伺服器委託瀏覽器存儲在客戶端裡的一些數據,而這些數據通常都會記錄用戶的關鍵識別信息。所以Cookie需要用一些其他的手段用來保護,防止外洩或者竊取,這些手段就是Cookie的屬性。

下面我就簡單演示一下這幾個參數的用法及現象。

Path

設置為cookie.setPath("/testCookies"),接下來我們訪問http://localhost:8005/testCookies,我們可以看到在左邊和我們指定的路徑是一樣的,所以Cookie才在請求頭中出現,接下來我們訪問http://localhost:8005,我們發現沒有Cookie欄位了,這就是Path控制的路徑。

Domain

設置為cookie.setDomain("localhost"),接下來我們訪問http://localhost:8005/testCookies我們發現下圖中左邊的是有Cookie的欄位的,但是我們訪問http://172.16.42.81:8005/testCookies,看下圖的右邊可以看到沒有Cookie的欄位了。這就是Domain控制的域名發送Cookie。

接下來的幾個參數就不一一演示了,相信到這裡大家應該對Cookie有一些了解了。

Session

> Cookie是存儲在客戶端方,Session是存儲在服務端方,客戶端只存儲SessionId在上面我們了解了什麼是Cookie,既然瀏覽器已經通過Cookie實現了有狀態這一需求,那麼為什麼又來了一個Session呢?這裡我們想像一下,如果將帳戶的一些信息都存入Cookie中的話,一旦信息被攔截,那麼我們所有的帳戶信息都會丟失掉。所以就出現了Session,在一次會話中將重要信息保存在Session中,瀏覽器只記錄SessionId一個SessionId對應一次會話請求。

@RequestMapping("/testSession")

@ResponseBody

public String testSession(HttpSession session){

session.setAttribute("testSession","this is my session");

return "testSession";

}

@RequestMapping("/testGetSession")

@ResponseBody

public String testGetSession(HttpSession session){

Object testSession = session.getAttribute("testSession");

return String.valueOf(testSession);

}

這裡我們寫一個新的方法來測試Session是如何產生的,我們在請求參數中加上HttpSession session,然後再瀏覽器中輸入http://localhost:8005/testSession進行訪問可以看到在伺服器的返回頭中在Cookie中生成了一個SessionId。然後瀏覽器記住此SessionId下次訪問時可以帶著此Id,然後就能根據此Id找到存儲在服務端的信息了。

此時我們訪問路徑http://localhost:8005/testGetSession,發現得到了我們上面存儲在Session

中的信息。那麼Session什麼時候過期呢?

客戶端:和

Cookie過期一致,如果沒設置,默認是關了瀏覽器就沒了,即再打開瀏覽器的時候初次請求頭中是沒有SessionId了。服務端:服務端的過期是真的過期,即伺服器端的Session存儲的數據結構多久不可用了,默認是30分鐘。

既然我們知道了Session是在服務端進行管理的,那麼或許你們看到這有幾個疑問,Session

是在在哪創建的?Session是存儲在什麼數據結構中?接下來帶領大家一起看一下Session是如何被管理的。

Session的管理是在容器中被管理的,什麼是容器呢?Tomcat、Jetty等都是容器。接下來我們拿最常用的Tomcat為例來看下Tomcat是如何管理Session的。在ManageBase的createSession是用來創建Session的。

@Override

public Session createSession(String sessionId) {

//首先判斷Session數量是不是到了最大值,最大Session數可以通過參數設置

if ((maxActiveSessions >= 0) &&

(getActiveSessions() >= maxActiveSessions)) {

rejectedSessions++;

throw new TooManyActiveSessionsException(

sm.getString("managerBase.createSession.ise"),

maxActiveSessions);

}

// 重用或者創建一個新的Session對象,請注意在Tomcat中就是StandardSession

// 它是HttpSession的具體實現類,而HttpSession是Servlet規範中定義的接口

Session session = createEmptySession();

// 初始化新Session的值

session.setNew(true);

session.setValid(true);

session.setCreationTime(System.currentTimeMillis());

// 設置Session過期時間是30分鐘

session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);

String id = sessionId;

if (id == null) {

id = generateSessionId();

}

session.setId(id);// 這裡會將Session添加到ConcurrentHashMap中

sessionCounter++;

//將創建時間添加到LinkedList中,並且把最先添加的時間移除

//主要還是方便清理過期Session

SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);

synchronized (sessionCreationTiming) {

sessionCreationTiming.add(timing);

sessionCreationTiming.poll();

}

return session

}

到此我們明白了Session是如何創建出來的,創建出來後Session會被保存到一個ConcurrentHashMap中。可以看StandardSession類。

protected Map<string, session> sessions = new ConcurrentHashMap&lt;&gt;();

到這裡大家應該對Session有簡單的了解了。

> Session是存儲在Tomcat的容器中,所以如果後端機器是多臺的話,因此多個機器間是無法共享Session的,此時可以使用Spring提供的分布式Session的解決方案,是將Session放在了Redis中。

Token

Session是將要驗證的信息存儲在服務端,並以SessionId和數據進行對應,SessionId由客戶端存儲,在請求時將SessionId也帶過去,因此實現了狀態的對應。而Token是在服務端將用戶信息經過Base64Url編碼過後傳給在客戶端,每次用戶請求的時候都會帶上這一段信息,因此服務端拿到此信息進行解密後就知道此用戶是誰了,這個方法叫做JWT(Json Web Token)。

>Token相比較於Session的優點在於,當後端系統有多臺時,由於是客戶端訪問時直接帶著數據,因此無需做共享數據的操作。

Token的優點

簡潔:可以通過URL,POST參數或者是在HTTP頭參數發送,因為數據量小,傳輸速度也很快自包含:由於串包含了用戶所需要的信息,避免了多次查詢資料庫因為Token是以Json的形式保存在客戶端的,所以JWT是跨語言的不需要在服務端保存會話信息,特別適用於分布式微服務JWT的結構

實際的JWT大概長下面的這樣,它是一個很長的字符串,中間用.分割成三部分

JWT是有三部分組成的

Header

是一個Json對象,描述JWT的元數據,通常是下面這樣子的

{ "alg": "HS256", "typ": "JWT"}

上面代碼中,alg屬性表示籤名的算法(algorithm),默認是 HMAC SHA256(寫成 HS256);typ屬性表示這個令牌(token)的類型(type),JWT 令牌統一寫為JWT。 最後,將上面的 JSON 對象使用 Base64URL 算法轉成字符串。

> JWT 作為一個令牌(token),有些場合可能會放到 URL(比如 api.example.com/?token=xxx)。Base64 有三個字符+、/和=,在 URL 裡面有特殊含義,所以要被替換掉:=被省略、+替換成-,/替換成_ 。這就是 Base64URL 算法。

Payload

Payload部分也是一個Json對象,用來存放實際需要傳輸的數據,JWT官方規定了下面幾個官方的欄位供選用。

iss (issuer):籤發人exp (expiration time):過期時間sub (subject):主題aud (audience):受眾nbf (Not Before):生效時間iat (Issued At):籤發時間jti (JWT ID):編號當然除了官方提供的這幾個欄位我們也能夠自己定義私有欄位,下面就是一個例子

{ "name": "xiaoMing", "age": 14}

默認情況下JWT是不加密的,任何人只要在網上進行Base64解碼就可以讀到信息,所以一般不要將秘密信息放在這個部分。這個Json對象也要用

Base64URL

算法轉成字符串

Signature

Signature部分是對前面的兩部分的數據進行籤名,防止數據篡改。

首先需要定義一個秘鑰,這個秘鑰只有伺服器才知道,不能洩露給用戶,然後使用Header中指定的籤名算法(默認情況是HMAC SHA256),算出籤名以後將Header、Payload、Signature三部分拼成一個字符串,每個部分用

.

分割開來,就可以返給用戶了。

> HS256可以使用單個密鑰為給定的數據樣本創建籤名。當消息與籤名一起傳輸時,接收方可以使用相同的密鑰來驗證籤名是否與消息匹配。

Java中如何使用Token

上面我們介紹了關於JWT的一些概念,接下來如何使用呢?首先在項目中引入Jar包compile('io.jsonwebtoken:jjwt:0.9.0')然後編碼如下

// 籤名算法 ,將對token進行籤名

SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

// 通過秘鑰籤名JWT

byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("SECRET");

Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());

Map<string,object> claimsMap = new HashMap&lt;&gt;();

claimsMap.put("name","xiaoMing");

claimsMap.put("age",14);

JwtBuilder builderWithSercet = Jwts.builder()

.setSubject("subject")

.setIssuer("issuer")

.addClaims(claimsMap)

.signWith(signatureAlgorithm, signingKey);

System.out.printf(builderWithSercet.compact());

發現輸出的Token如下eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwibmFtZSI6InhpYW9NaW5nIiwiYWdlIjoxNH0.3KOWQ-oYvBSzslW5vgB1D-JpCwS-HkWGyWdXCP5l3Ko

此時在網上隨便找個Base64解碼的網站就能將信息解碼出來

總結

相信大家看到這應該對Cookie、Session、Token有一定的了解了,接下來再回顧一下重要的知識點

Cookie是存儲在客戶端的Session是存儲在服務端的,可以理解為一個狀態列表。擁有一個唯一會話標識SessionId。可以根據SessionId在服務端查詢到存儲的信息。Session會引發一個問題,即後端多臺機器時Session共享的問題,解決方案可以使用Spring提供的框架。Token類似一個令牌,無狀態的,服務端所需的信息被Base64編碼後放到Token中,伺服器可以直接解碼出其中的數據。(以上信息如有侵權,請聯繫刪除謝謝!)

相關焦點

  • Cookie、Session、Token那點事兒
    作者:騎小豬看流星連結前言:新公司項目中使用到了Cookie,在各大Android技術討論群向前輩們取經討論這cookie、session、token這仨哥們的時候,很多開發者說法不一各抒已見2、cookie不是很安全,別人可以分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session。3、session會在一定時間內保存在伺服器上。當訪問增多,會比較佔用你伺服器的性能,考慮到減輕伺服器性能方面,應當使用cookie。
  • Cookie, Session, Token,WebStorage你懂多少?
    只有一小部分同學能答出來要用cookie和session.再問,有了cookie為什麼還要session?更少一部分人能答出來安全。再問,不要cookie行不行?能答出URL重寫的已經不錯了。對於高級的測試,再繼續深入,session保存在伺服器內存中,隨著用戶的增多,伺服器撐不住了怎麼辦?假設我使用了集群服務怎麼辦?
  • 會話技術 Cookie和Session
    cookie:   HttpServletRequest.getCookies()  註:不同網站向同一個客戶端寫的cookie的名稱一致,可以通過cookie的path屬性進行區分    cookie的默認存活時間是會話範圍。
  • session原理終極版-一文弄懂session會話與cookie 秒殺CSDN
    首先我們來看一下瀏覽器保存的cookie長什麼樣子。通過任意抓包工具,抓取一個需要登錄的網站的cookie,如下圖:Session,cookie類似於鍵值對,可以保存你的token,其他一些有用的信息,其本質是存在瀏覽器中的鍵值對字符串。必須要指出的是裡面的信息都是字符串。
  • 淺談Cookie與Session技術
    四、session技術(伺服器端)(1)什麼是session?a、session是一種伺服器端的狀態管理技術。b、session是基於cookie的技術。且session也是通過cookie來實現發送到瀏覽器內存中的。所以可以考慮用cookie來替換該session。如果用戶在中途關閉瀏覽器的話,那麼session就隨著瀏覽器內存的釋放而釋放,那麼如果想持久化session的話,可以考慮使用cookie技術。Step1、獲取sessionID。
  • 一篇故事看懂從 session-cookie 到 JWT 的技術演變
    怎麼沒聽過這號人物」「我也沒見過,等等看吧」session-cookie時代到底是什麼問題,讓我們兄弟幾個如此著急上火?事情還得從多年以前說起······那時候,這倆兄弟還沒來,就我一個web伺服器,每天處理的不過是一些靜態資源文件,像HTML、CSS、JS、圖片等等,日子過的清閒自在。
  • 一篇理解cookie、session、localStorage和sessionStorage
    試題6: 在chrome上登陸的cookie,safari會帶上cookie嗎?解決上面6個問題,首先要依此了解cookie、session、localStorage和sessionStorage的各個用法:1. Cookie是伺服器發送到用戶瀏覽器並保存在本地的一小塊數據。2.
  • session和cookie魅力所在
    實現Web應用的技術核心http協議是一個無狀態的協,為了讓Web應用開發保持狀態,就出現了保持http連結的狀態的兩種技術:一個是cookie技術,另一個是session技術。cookie技術是客戶端解決方案(HTML5之後有了更好的替代品),其主要的特點是,伺服器發給客戶端的特殊信息以文本的形式存放在客戶端,之後客戶端每次向服務端發送請求時都會帶上這些信息。
  • 關於Cookie與session會話技術的示例
    Session是伺服器端技術,利用這個技術,伺服器在運行時可以為每一個用戶的瀏覽器創建一個其獨享的session對象,由於session為用戶瀏覽器獨享,所以用戶在訪問伺服器的web資源時,可以把各自的數據放在各自的session中,當用戶再去訪問伺服器中的其它web資源時,其它web資源再從用戶各自的
  • 淺談cookie,sessionStorage,localStorage
    優點,缺點和瀏覽器支持和 Local Storage 一樣sessionStorage、localStorage、cookie都是在瀏覽器端存儲的數據,其中sessionStorage的概念很特別,引入了一個「
  • session與cookie引發的一個小故事
    首先加載頁面時去得到驗證碼,後臺將驗證碼數字存入到session中,然後在登陸時把前端傳入的驗證碼數字同後臺取出的碼進行比較,比較之前首先把原來的session移除掉。若相同則驗證通過,不同則驗證不通過然後重新請求。這個流程本來是沒有什麼問題的,然而自己突然想到這裡會不會有點問題呢?session在並發時會不會出現覆蓋的情況呢?然後就動手開始測試。
  • cookie和session原來還有這樣的關係
    那麼問題來了,我怎麼登錄,登錄成功後,刷新下,伺服器就不認識我了,不展示我的信息了,這怎麼能行,於是cookie就產生了,cookie是存在客戶端的,最常見的就是瀏覽器了,你第一次訪問頁面的時候,伺服器會返回個cookie給你,這個cookie其實就是sessionId,並存於客戶端,第二次的時候,你刷新頁面的時候,瀏覽器就會帶上之前的cookie,cookie就像通行證,每人一個,無論誰訪問都必須攜帶自己通行證
  • 面試題: 聊聊 session 和 cookie 的區別
    伺服器驗證通過後,在當前對話 (session) 裡面保存相關數據,比如用戶角色,登陸時間等伺服器向用戶返回一個session_id,寫入用戶的cookie用戶隨後的每一次請求,都會通過cookie,將session_id傳回伺服器服務端收到
  • PHP技巧:關於cookie和session的分析
    PHP的COOKIEcookie 是一種在遠程瀏覽器端儲存數據並以此來跟蹤和識別用戶的機制。PHP在http協議的頭信息裡發送cookie, 因此 setcookie() 函數必須在其它信息被輸出到瀏覽器前調用,這和對 header() 函數的限制類似。
  • localStorage、sessionStorage有什麼區別?
    對比cookie:cookie會與伺服器通信;storage只存在客服端,不參與伺服器通信;同樣受同源策略影響,只有在域名一致的情況下才能查看到對應的數據;navigator.cookieEnabled檢測是否啟用了cookie,也就說cookie
  • (建議收藏)|Spring Boot集成JSON Web Token(JWT)
    一:認證在了解JWT之前先來回顧一下傳統session認證和基於token認證。## 1.1 傳統session認證http協議是一種無狀態協議,即瀏覽器發送請求到伺服器,伺服器是不知道這個請求是哪個用戶發來的。
  • Springboot中登錄後關於cookie和session攔截案例
    2、每次登錄的時候都要進資料庫校驗下帳戶名和密碼,只是加了cookie 或session驗證後;比如登錄頁面A,登錄成功後進入頁面B,若此時cookie過期,在頁面B中新的請求url到頁面c,系統會讓它回到初始的登錄頁面。(類似單點登錄sso(single sign on))。
  • [接口測試_B] 09 requests中Cookie和會話對象session處理
    因此,cookie和session存在的作用是進行狀態管理。客戶端怎麼能對上這個session暗號?1)、在客戶端給服務端發送請求後,服務端會根據請求信息生成session,同時生成一個session_id,通過cookie返回給客戶端;2)、客戶端再次向服務端發送請求時,會通過cookie將這個session_id發送給服務端,這樣就對上了session的暗號。
  • 網站安全公司告訴您什麼是session安全
    這一部分內容的重中之重是session和cookie,客戶在安全使用app系統時,如何根據客戶的身份提供不同的功能和相關數據,每個人都有這樣的體驗。例如,訪問淘寶,不會把自己喜歡的商品加入別人的購物車,如何區分不同的客戶?打開任何網站,抓住包看,cookie的欄位都存在。
  • 小白必讀:閒話HTTP短連接中的Session和Token
    很多文章動輒長篇大論、高屋建瓴地從底層協議再到上層分布式應用式的講解,根本不適合傻白甜程式設計師,本文的寫作目的是以最白話地方式,通俗易懂的為你講清HTTP協議中的Session和Token等概念,希望讀完全文,您仍能滿懷信心,繼續義無反顧地跳入程式設計師這個職業深坑 ^_^。