Session和Cookie這兩個概念,在學習java web開發之初,大多數人就已經接觸過了。最近在研究跨域單點登錄的實現時,發現對于Session和Cookie的了解,并不是很深入,所以打算寫兩篇文章記錄一下自己的理解。在我們的應用集成Spring Session之前,先補充一點Session和Cookie的關鍵知識。
## Session與Cookie基礎
由于http協議是無狀態的協議,為了能夠記住請求的狀態,于是引入了Session和Cookie的機制。我們應該有一個很明確的概念,那就是Session是存在于服務器端的,在單體式應用中,他是由tomcat管理的,存在于tomcat的內存中,當我們為了解決分布式場景中的session共享問題時,引入了redis,其共享內存,以及支持key自動過期的特性,非常契合session的特性,我們在企業開發中最常用的也就是這種模式。但是只要你愿意,也可以選擇存儲在JDBC,Mongo中,這些,spring都提供了默認的實現,在大多數情況下,我們只需要引入配置即可。而Cookie則是存在于客戶端,更方便理解的說法,可以說存在于瀏覽器。Cookie并不常用,至少在我不長的web開發生涯中,并沒有什么場景需要我過多的關注Cookie。http協議允許從服務器返回Response時攜帶一些Cookie,并且同一個域下對Cookie的數量有所限制,之前說過Session的持久化依賴于服務端的策略,而Cookie的持久化則是依賴于本地文件。雖然說Cookie并不常用,但是有一類特殊的Cookie卻是我們需要額外關注的,那便是與Session相關的sessionId,他是真正維系客戶端和服務端的橋梁。
## 代碼示例
用戶發起請求,服務器響應請求,并做一些用戶信息的處理,隨后返回響應給用戶;用戶再次發起請求,攜帶sessionId,服務器便能夠識別,這個用戶就是之前請求的那個。
使用Springboot編寫一個非常簡單的服務端,來加深對其的理解。需求很簡單,當瀏覽器訪問localhost:8080/test/cookie?browser=xxx時,如果沒有獲取到session,則將request中的browser存入session;如果獲取到session,便將session中的browser值輸出。順便將request中的所有cookie打印出來。
~~~
@Controller
public class CookieController {
@RequestMapping("/test/cookie")
public String cookie(@RequestParam("browser") String browser, HttpServletRequest request, HttpSession session) {
//取出session中的browser
Object sessionBrowser = session.getAttribute("browser");
if (sessionBrowser == null) {
System.out.println("不存在session,設置browser=" + browser);
session.setAttribute("browser", browser);
} else {
System.out.println("存在session,browser=" + sessionBrowser.toString());
}
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
System.out.println(cookie.getName() + " : " + cookie.getValue());
}
}
return "index";
}
}
~~~
我們沒有引入其他任何依賴,看看原生的session機制是什么。
1 使用chrome瀏覽器,訪問localhost:8080/test/cookie?browser=chrome,控制臺輸出如下:
`Session Info: 不存在session,設置browser=chrome`
既沒有session,也沒有cookie,并且根據我們將browser=chrome已經設置到了session中。
再次訪問同樣的地址,控制臺輸出如下:
~~~
Session Info: 存在session,browser=chrome
Cookie Info: JSESSIONID : 4CD1D96E04FC390EA6C60E8C40A636AF
~~~
多次訪問之后,控制臺依舊打印出同樣的信息。
稍微解讀下這個現象,可以驗證一些結論。當服務端往session中保存一些數據時,Response中自動添加了一個Cookie:JSESSIONID:xxxx,再后續的請求中,瀏覽器也是自動的帶上了這個Cookie,服務端根據Cookie中的JSESSIONID取到了對應的session。這驗證了一開始的說法,客戶端服務端是通過JSESSIONID進行交互的,并且,添加和攜帶key為JSESSIONID的Cookie都是tomcat和瀏覽器自動幫助我們完成的,這很關鍵。
2 使用360瀏覽器,訪問localhost:8080/test/cookie?browser=360
第一次訪問:
`Session Info: 不存在session,設置browser=360`
后續訪問:
~~~
Session Info: 存在session,browser=360
Cookie Info: JSESSIONID : 320C21A645A160C4843D076204DA2F40
~~~
為什么要再次使用另一個瀏覽器訪問呢?先賣個關子,我們最起碼可以得出結論,不同瀏覽器,訪問是隔離的,甚至重新打開同一個瀏覽器,JSESSIONID也是不同的。
## 安全問題
其實上述的知識點,都是非常淺顯的,之所以啰嗦一句,是為了引出這一節的內容,以及方便觀察后續我們引入Spring Session之后的發生的變化。
還記得上一節的代碼示例中,我們使用了兩個瀏覽器:
* chrome瀏覽器訪問時,JSESSIONID為4CD1D96E04FC390EA6C60E8C40A636AF,后端session記錄的值為:browser=chrome
* 360瀏覽器訪問時,JSESSIONID為320C21A645A160C4843D076204DA2F40,后端session記錄的值為:browser=360。
我們使用chrome插件Edit this Cookie,將chrome瀏覽器中的JSESSIONID修改為360瀏覽器中的值

同樣訪問原來的端點:localhost:8080/test/cookie?browser=chrome,得到的輸出如下:
~~~
存在session,browser=360
JSESSIONID : 320C21A645A160C4843D076204DA2F40
~~~
證實了一點,存放在客戶端的Cookie的確是存在安全問題的,我們使用360的JSESSIONID“騙”過了服務器。畢竟,服務器只能通過Cookie中的JSESSIONID來辨別身份。(這提示我們不要在公共場合保存Cookie信息,現在的瀏覽器在保存Cookie時通常會讓你確定一次)。
- java
- 設計模式
- 設計模式總覽
- 設計原則
- 工廠方法模式
- 抽象工廠模式
- 單例模式
- 建造者模式
- 原型模式
- 適配器模式
- 裝飾者模式
- 代理模式
- 外觀模式
- 橋接模式
- 組合模式
- 享元模式
- 策略模式
- 模板方法模式
- 觀察者模式
- 迭代子模式
- 責任鏈模式
- 命令模式
- 備忘錄模式
- 狀態模式
- 訪問者模式
- 中介者模式
- 解釋器模式
- 附錄
- JVM相關
- JVM內存結構
- Java虛擬機的內存組成以及堆內存介紹
- Java堆和棧
- 附錄-數據結構的堆棧和內存分配的堆區棧區的區別
- Java內存之Java 堆
- Java內存之虛擬機和內存區域概述
- Java 內存之方法區和運行時常量池
- Java 內存之直接內存(堆外內存)
- JAVA內存模型
- Java內存模型介紹
- 內存模型如何解決緩存一致性問題
- 深入理解Java內存模型——基礎
- 深入理解Java內存模型——重排序
- 深入理解Java內存模型——順序一致性
- 深入理解Java內存模型——volatile
- 深入理解Java內存模型——鎖
- 深入理解Java內存模型——final
- 深入理解Java內存模型——總結
- 內存可見性
- JAVA對象模型
- JVM內存結構 VS Java內存模型 VS Java對象模型
- Java的對象模型
- Java的對象頭
- HotSpot虛擬機
- HotSpot虛擬機對象探秘
- 深入分析Java的編譯原理
- Java虛擬機的鎖優化技術
- 對象和數組并不是都在堆上分配內存的
- 垃圾回收
- JVM內存管理及垃圾回收
- JVM 垃圾回收器工作原理及使用實例介紹
- JVM內存回收理論與實現(對象存活的判定)
- JVM參數及調優
- CMS GC日志分析
- JVM實用參數(一)JVM類型以及編譯器模式
- JVM實用參數(二)參數分類和即時(JIT)編譯器診斷
- JVM實用參數(三)打印所有XX參數及值
- JVM實用參數(四)內存調優
- JVM實用參數(五)新生代垃圾回收
- JVM實用參數(六) 吞吐量收集器
- JVM實用參數(七)CMS收集器
- JVM實用參數(八)GC日志
- Java性能調優原則
- JVM 優化經驗總結
- 面試題整理
- 面試題1
- java日志規約
- Spring安全
- OAtuth2.0簡介
- Spring Session 簡介(一)
- Spring Session 簡介(二)
- Spring Session 簡介(三)
- Spring Security 簡介(一)
- Spring Security 簡介(二)
- Spring Security 簡介(三)
- Spring Security 簡介(四)
- Spring Security 簡介(五)
- Spring Security Oauth2 (一)
- Spring Security Oauth2 (二)
- Spring Security Oauth2 (三)
- SpringBoot
- Shiro
- Shiro和Spring Security對比
- Shiro簡介
- Session、Cookie和Cache
- Web Socket
- Spring WebFlux