自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文徹底搞懂Cookie、Session、Token到底是什么

開發(fā) 前端
在了解這三個概念之前我們先要了解HTTP是無狀態(tài)的Web服務(wù)器,什么是無狀態(tài)呢?就像上面夏洛特?zé)乐薪?jīng)典的一幕對話一樣,一次對話完成后下一次對話完全不知道上一次對話發(fā)生了什么。

Cookie

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

大爺:馬都什么?

夏洛:馬冬梅。

大爺:什么都沒???

夏洛:馬冬梅啊。

大爺:馬什么沒?

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

在了解這三個概念之前我們先要了解HTTP是無狀態(tài)的Web服務(wù)器,什么是無狀態(tài)呢?就像上面夏洛特?zé)乐薪?jīng)典的一幕對話一樣,一次對話完成后下一次對話完全不知道上一次對話發(fā)生了什么。如果在Web服務(wù)器中只是用來管理靜態(tài)文件還好說,對方是誰并不重要,把文件從磁盤中讀取出來發(fā)出去即可。但是隨著網(wǎng)絡(luò)的不斷發(fā)展,比如電商中的購物車只有記住了用戶的身份才能夠執(zhí)行接下來的一系列動作。所以此時就需要我們無狀態(tài)的服務(wù)器記住一些事情。

那么Web服務(wù)器是如何記住一些事情呢?既然Web服務(wù)器記不住東西,那么我們就在外部想辦法記住,相當(dāng)于服務(wù)器給每個客戶端都貼上了一個小紙條。上面記錄了服務(wù)器給我們返回的一些信息。然后服務(wù)器看到這張小紙條就知道我們是誰了。那么Cookie是誰產(chǎn)生的呢?Cookies是由服務(wù)器產(chǎn)生的。接下來我們描述一下Cookie產(chǎn)生的過程

  1.  瀏覽器第一次訪問服務(wù)端時,服務(wù)器此時肯定不知道他的身份,所以創(chuàng)建一個獨特的身份標(biāo)識數(shù)據(jù),格式為key=value,放入到Set-Cookie字段里,隨著響應(yīng)報文發(fā)給瀏覽器。
  2.  瀏覽器看到有Set-Cookie字段以后就知道這是服務(wù)器給的身份標(biāo)識,于是就保存起來,下次請求時會自動將此key=value值放入到Cookie字段中發(fā)給服務(wù)端。
  3.  服務(wù)端收到請求報文后,發(fā)現(xiàn)Cookie字段中有值,就能根據(jù)此值識別用戶的身份然后提供個性化的服務(wù)。

接下來我們用代碼演示一下服務(wù)器是如何生成,我們自己搭建一個后臺服務(wù)器,這里我用的是SpringBoot搭建的,并且寫入SpringMVC的代碼如下。 

  1. @RequestMapping("/testCookies")  
  2. public String cookies(HttpServletResponse response){  
  3.     response.addCookie(new Cookie("testUser","xxxx"));  
  4.     return "cookies";  

項目啟動以后我們輸入路徑http://localhost:8005/testCookies,然后查看發(fā)的請求??梢钥吹较旅婺菑垐D使我們首次訪問服務(wù)器時發(fā)送的請求,可以看到服務(wù)器返回的響應(yīng)中有Set-Cookie字段。而里面的key=value值正是我們服務(wù)器中設(shè)置的值。

接下來我們再次刷新這個頁面可以看到在請求體中已經(jīng)設(shè)置了Cookie字段,并且將我們的值也帶過去了。這樣服務(wù)器就能夠根據(jù)Cookie中的值記住我們的信息了。

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

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

  1.  在計算機(jī)打開Chrome
  2.  在右上角,一次點擊更多圖標(biāo)->設(shè)置
  3.  在底部,點擊高級
  4.  在隱私設(shè)置和安全性下方,點擊網(wǎng)站設(shè)置
  5.  依次點擊Cookie->查看所有Cookie和網(wǎng)站數(shù)據(jù)

然后可以根據(jù)域名進(jìn)行搜索所管理的Cookie數(shù)據(jù)。所以是瀏覽器替你管理了Cookie的數(shù)據(jù),如果此時你換成了Firefox等其他的瀏覽器,因為Cookie剛才是存儲在Chrome里面的,所以服務(wù)器又蒙圈了,不知道你是誰,就會給Firefox再次貼上小紙條。

Cookie中的參數(shù)設(shè)置

說到這里,應(yīng)該知道了Cookie就是服務(wù)器委托瀏覽器存儲在客戶端里的一些數(shù)據(jù),而這些數(shù)據(jù)通常都會記錄用戶的關(guān)鍵識別信息。所以Cookie需要用一些其他的手段用來保護(hù),防止外泄或者竊取,這些手段就是Cookie的屬性。

參數(shù)名 作用 后端設(shè)置方法
Max-Age 設(shè)置cookie的過期時間,單位為秒 cookie.setMaxAge(10)
Domain 指定了Cookie所屬的域名 cookie.setDomain("")
Path 指定了Cookie所屬的路徑 cookie.setPath("");
HttpOnly 告訴瀏覽器此Cookie只能靠瀏覽器Http協(xié)議傳輸,禁止其他方式訪問 cookie.setHttpOnly(true)
Secure 告訴瀏覽器此Cookie只能在Https安全協(xié)議中傳輸,如果是Http則禁止傳輸 cookie.setSecure(true)

下面我就簡單演示一下這幾個參數(shù)的用法及現(xiàn)象。

Path

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

Domain

設(shè)置為cookie.setDomain("localhost"),接下來我們訪問http://localhost:8005/testCookies我們發(fā)現(xiàn)下圖中左邊的是有Cookie的字段的,但是我們訪問http://172.16.42.81:8005/testCookies,看下圖的右邊可以看到?jīng)]有Cookie的字段了。這就是Domain控制的域名發(fā)送Cookie。

接下來的幾個參數(shù)就不一一演示了,相信到這里大家應(yīng)該對Cookie有一些了解了。

Session

> Cookie是存儲在客戶端方,Session是存儲在服務(wù)端方,客戶端只存儲SessionId

在上面我們了解了什么是Cookie,既然瀏覽器已經(jīng)通過Cookie實現(xiàn)了有狀態(tài)這一需求,那么為什么又來了一個Session呢?這里我們想象一下,如果將賬戶的一些信息都存入Cookie中的話,一旦信息被攔截,那么我們所有的賬戶信息都會丟失掉。所以就出現(xiàn)了Session,在一次會話中將重要信息保存在Session中,瀏覽器只記錄SessionId一個SessionId對應(yīng)一次會話請求。

 

  1. @RequestMapping("/testSession")  
  2. @ResponseBody  
  3. public String testSession(HttpSession session){  
  4.     session.setAttribute("testSession","this is my session");  
  5.     return "testSession";  
  6.  
  7. @RequestMapping("/testGetSession")  
  8. @ResponseBody  
  9. public String testGetSession(HttpSession session){  
  10.     Object testSession = session.getAttribute("testSession");  
  11.     return String.valueOf(testSession);  

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

此時我們訪問路徑http://localhost:8005/testGetSession,發(fā)現(xiàn)得到了我們上面存儲在Session中的信息。那么Session什么時候過期呢?

  •  客戶端:和Cookie過期一致,如果沒設(shè)置,默認(rèn)是關(guān)了瀏覽器就沒了,即再打開瀏覽器的時候初次請求頭中是沒有SessionId了。
  •  服務(wù)端:服務(wù)端的過期是真的過期,即服務(wù)器端的Session存儲的數(shù)據(jù)結(jié)構(gòu)多久不可用了,默認(rèn)是30分鐘。

既然我們知道了Session是在服務(wù)端進(jìn)行管理的,那么或許你們看到這有幾個疑問,Session是在在哪創(chuàng)建的?Session是存儲在什么數(shù)據(jù)結(jié)構(gòu)中?接下來帶領(lǐng)大家一起看一下Session是如何被管理的。

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

  1. @Override  
  2. public Session createSession(String sessionId) {  
  3.     //首先判斷Session數(shù)量是不是到了最大值,最大Session數(shù)可以通過參數(shù)設(shè)置  
  4.     if ((maxActiveSessions >= 0) &&  
  5.             (getActiveSessions() >= maxActiveSessions)) {  
  6.         rejectedSessions++;  
  7.         throw new TooManyActiveSessionsException(  
  8.                 sm.getString("managerBase.createSession.ise"),  
  9.                 maxActiveSessions);  
  10.     }  
  11.     // 重用或者創(chuàng)建一個新的Session對象,請注意在Tomcat中就是StandardSession  
  12.     // 它是HttpSession的具體實現(xiàn)類,而HttpSession是Servlet規(guī)范中定義的接口  
  13.     Session session = createEmptySession();  
  14.     // 初始化新Session的值  
  15.     session.setNew(true);  
  16.     session.setValid(true);  
  17.     session.setCreationTime(System.currentTimeMillis());  
  18.     // 設(shè)置Session過期時間是30分鐘  
  19.     session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);  
  20.     String id = sessionId 
  21.     if (id == null) {  
  22.         id = generateSessionId();  
  23.     }  
  24.     session.setId(id);// 這里會將Session添加到ConcurrentHashMap中  
  25.     sessionCounter++;  
  26.     //將創(chuàng)建時間添加到LinkedList中,并且把最先添加的時間移除  
  27.     //主要還是方便清理過期Session  
  28.     SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);  
  29.     synchronized (sessionCreationTiming) { 
  30.          sessionCreationTiming.add(timing);  
  31.         sessionCreationTiming.poll(); 
  32.      }  
  33.     return session  

到此我們明白了Session是如何創(chuàng)建出來的,創(chuàng)建出來后Session會被保存到一個ConcurrentHashMap中??梢钥碨tandardSession類。 

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

到這里大家應(yīng)該對Session有簡單的了解了。

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

Token

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

> Token相比較于Session的優(yōu)點在于,當(dāng)后端系統(tǒng)有多臺時,由于是客戶端訪問時直接帶著數(shù)據(jù),因此無需做共享數(shù)據(jù)的操作。

Token的優(yōu)點

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

JWT的結(jié)構(gòu)

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

JWT是有三部分組成的

Header

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

  1.  
  2.   "alg": "HS256",  
  3.   "typ": "JWT"  

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

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

Payload

Payload部分也是一個Json對象,用來存放實際需要傳輸?shù)臄?shù)據(jù),JWT官方規(guī)定了下面幾個官方的字段供選用。

  •  iss (issuer):簽發(fā)人
  •  exp (expiration time):過期時間
  •  sub (subject):主題
  •  aud (audience):受眾
  •  nbf (Not Before):生效時間
  •  iat (Issued At):簽發(fā)時間
  •  jti (JWT ID):編號

當(dāng)然除了官方提供的這幾個字段我們也能夠自己定義私有字段,下面就是一個例子 

  1.  
  2.   "name": "xiaoMing",  
  3.   "age": 14  

默認(rèn)情況下JWT是不加密的,任何人只要在網(wǎng)上進(jìn)行Base64解碼就可以讀到信息,所以一般不要將秘密信息放在這個部分。這個Json對象也要用Base64URL 算法轉(zhuǎn)成字符串

Signature

Signature部分是對前面的兩部分的數(shù)據(jù)進(jìn)行簽名,防止數(shù)據(jù)篡改。

首先需要定義一個秘鑰,這個秘鑰只有服務(wù)器才知道,不能泄露給用戶,然后使用Header中指定的簽名算法(默認(rèn)情況是HMAC SHA256),算出簽名以后將Header、Payload、Signature三部分拼成一個字符串,每個部分用.分割開來,就可以返給用戶了。

> HS256可以使用單個密鑰為給定的數(shù)據(jù)樣本創(chuàng)建簽名。當(dāng)消息與簽名一起傳輸時,接收方可以使用相同的密鑰來驗證簽名是否與消息匹配。

 

上面我們介紹了關(guān)于JWT的一些概念,接下來如何使用呢?首先在項目中引入Jar包 

  1. compile('io.jsonwebtoken:jjwt:0.9.0') 

然后編碼如下 

  1. // 簽名算法 ,將對token進(jìn)行簽名  
  2. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;  
  3. // 通過秘鑰簽名JWT  
  4. byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("SECRET");  
  5. Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());  
  6. Map<string,object> claimsMap = new HashMap&lt;&gt;();  
  7. claimsMap.put("name","xiaoMing");  
  8. claimsMap.put("age",14);  
  9. JwtBuilder builderWithSercet = Jwts.builder()  
  10.         .setSubject("subject")  
  11.         .setIssuer("issuer")  
  12.         .addClaims(claimsMap)  
  13.         .signWith(signatureAlgorithm, signingKey);  
  14. System.out.printf(builderWithSercet.compact()); 

發(fā)現(xiàn)輸出的Token如下 

  1. eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwibmFtZSI6InhpYW9NaW5nIiwiYWdlIjoxNH0.3KOWQ-oYvBSzslW5vgB1D-JpCwS-HkWGyWdXCP5l3Ko 

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

總結(jié)

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

  •  Cookie是存儲在客戶端的
  •  Session是存儲在服務(wù)端的,可以理解為一個狀態(tài)列表。擁有一個唯一會話標(biāo)識SessionId??梢愿鶕?jù)SessionId在服務(wù)端查詢到存儲的信息。
  •  Session會引發(fā)一個問題,即后端多臺機(jī)器時Session共享的問題,解決方案可以使用Spring提供的框架。
  •  Token類似一個令牌,無狀態(tài)的,服務(wù)端所需的信息被Base64編碼后放到Token中,服務(wù)器可以直接解碼出其中的數(shù)據(jù)。 

 

責(zé)任編輯:龐桂玉 來源: 中國開源
相關(guān)推薦

2019-11-06 17:30:57

cookiesessionWeb

2021-08-09 08:53:30

HTTP狀態(tài)化協(xié)議

2021-01-18 13:05:52

Serverless Serverfull FaaS

2020-10-27 10:26:03

編程開發(fā)Java

2019-11-07 10:37:36

CookieSessionToken

2019-06-11 14:45:25

2021-06-30 08:45:02

內(nèi)存管理面試

2020-03-18 14:00:47

MySQL分區(qū)數(shù)據(jù)庫

2022-06-07 10:13:22

前端沙箱對象

2020-12-07 06:19:50

監(jiān)控前端用戶

2021-07-08 10:08:03

DvaJS前端Dva

2021-02-28 20:53:37

Cookie存儲瀏覽器

2023-12-11 11:29:35

2024-08-08 14:57:32

2022-04-11 10:56:43

線程安全

2024-11-26 08:31:36

2013-03-20 09:16:48

2023-11-23 06:50:08

括號

2020-12-18 09:36:01

JSONP跨域面試官

2023-04-12 08:38:44

函數(shù)參數(shù)Context
點贊
收藏

51CTO技術(shù)棧公眾號