Cookie
Cookie是一種小型的文本文件,由網站在用戶訪問時存儲在其計算機或移動設備上,Cookie主要用于跟蹤、識別和存儲有關用戶的信息。
簡單來說Cookie就是用來存儲某些后端發送給前端的數據,例如我們登陸后,后端會返回一個登錄憑證,這樣子你才能正常執行網站登錄之后的功能。
我們的session和token其實就大部分作為一個登錄憑證使用
我們Cookie就是來存儲類似的這種東西,我們每次在域名內跳轉的時候,我們都默認附加這個Cookie請求,這樣子我們就可以保存登錄狀態來操作
例如我是在bilibili這個域名登錄的
我點開其他視頻的時候,我是在這個域名內跳轉
例如這樣子,但是我們跳到了不同的界面,我們還是保持登錄狀態的,這就是Cookie的作用
Cookie可以在域名內跳轉的時候保存一些我們想保存的東西,
所以那種保持登錄狀態和7天免登錄就是Cookie的用處。
所以Cookie其實和Session和Token是不同的東西,我們不要搞混了
但是Session和Token是類似的東西,是一種保持登錄狀態的東西,是一種登錄憑證
Session
然后我們來講講Session
Session是我們的服務器里面的一個東西,例如我們的小貓咪Tomcat服務器
我們的Session是由我們的服務器生成,然后Session這個東西我們保存到我們的服務器里面,
我們Session會生成一個叫SessionId的東西返回給前端,然后如果我們檢測到我們由SessionId這個和東西我們就可以操作我們的服務器里面的Session
例如我們可以往我們的Session里面存東西,像下面那樣
看到了這個Context這個東西了嗎,這個東西就是可以做上下文的
我們存進上下文的東西是可以全局使用,調用的
這個的意思是,我們用Session來統計,其實不同的瀏覽器執行時,我們拿到的SeesionId是不同的,所以我就做了個簡單的登錄統計,我們往這個全局上下文的“olcount”存儲,如果session!=null,我們就加1,這個就是簡單的往Session的Context上下文里面存的東西邏輯
其實我們也可以直接往session里面存,session.set就行了
例如我們寫代碼的時候,像調用一些東西,例如我們登錄,然后像后面調用它的用戶名
我們就Session.set("username","kira"),我們往session里面存了個username的變量,變量的值是kira,然后我們后面寫邏輯的時候,想得到我們當前用戶的用戶名我們直接session.get("username"),就把kira這個用戶名給拿出來了
總的來說就是,Session是在我們的服務器生成的,然后我們生成一個SessionId給前端存儲到Cookie里,有了SessionId我們就可以操作我們的服務器里面對應的Session以及里面的方法
Seesion是一種服務器自己生成的東西,返回給前端的SeesionId是我們的登錄憑證
但其實Session有缺點,如果Seesion過多它會占用服務器的內存,然后Session的很多東西都是服務器生成的,我們這種后端很難靈活地操作和修改,例如它設定這個Seesion的過期時間為10分鐘,我們只想讓一個Session30分鐘過期,其他Seesion保持不變,我們只能直接修改服務器配置改成30分鐘,但修改服務器Seesion過期時間配置的話,其他所有的Seesion都會跟著修改過期時間,無法做到某個特例不同
Token
然后我們來講Token
Token是一種基于加密算法,由后端自己做的一種登錄憑證
而Seesion是一種服務器生成的東西,SessionId是服務器生成的登陸憑證
區別在于:一個是服務器規定好生成的,一個是后端自己基于加密算法做好的,我們的操作主體是不同的,一個是服務器,一個是后端
我們可以用UUID來隨機生成一個Token,UUID其實也是一種算法,例如我們這樣子,生成一個東西來當作Token
我們使用正確的密碼成功登錄之后,我們用生成的UUID,把它存到我們的Redis里面,設置例如30分鐘的過期時間
最重要的一點來了,我們要把這個東西返回給前端
我們一般都是,把這個Token(我是用UUID做的)存到請求頭里面,請求頭里的參數名是Authorization,把我們的uuid存到這個請求頭的變量里面
然后我們在全局攔截器里面弄一個操作邏輯,就是任何請求,我們都要有一個判斷就是判斷用戶是否是登錄狀態,如果我們的Authorization不為空,且uuid的值和后端里存的uuid可以對上,那么就可以確認這個用戶是登錄狀態的
怎么樣?之前我們是用SessionId來找到服務器對應session判斷用戶是否是登錄狀態,
現在是我們用Token去找對應的東西是否存在來判斷用戶是否是登錄狀態
所以Session和Token其實有很多類似的地方,但是Session里面可能有些操作方法什么的可以調用,不僅僅只有個SessionId作為登錄憑證,而Token大部分時間是做登錄憑證的,反正我還沒了解到Token的其他大用途。
還記得之前提到的Session的一個小問題嗎?
修改服務器Seesion過期時間配置的話,其他所有的Seesion都會跟著修改過期時間,無法做到某個特例不同
但是如果我們用Token然后存到我們的Redis里面的這個邏輯的話,我們可以用Redis來給不同的Token來設置過期時間,這樣子就可以設置不同的用戶的過期時間了是吧?
例如A用戶10分鐘過期,B用戶20分鐘過期,C用戶30分鐘過期
但是如果我們用session的話,我們無法做到這種多個不同的過期時間,我們只能統一所有的session都是一個過期時間,所以Token的優點就在這里。而且Token的話不會像Session那樣占用服務器內存,它只是一個小數據,我們存到數據庫里面使用,還可以隨意設置過期時間。
JWT
jwt其實就是token的另一種實現方式,上面的例子我是用UUID來演示我們的token的,然后存到redis里面設置過期時間
而JWT的話就更加簡便了,我就拿黑馬課程的這章節來舉例子
實戰篇-07_JWT令牌_嗶哩嗶哩_bilibili
里面提供了一個生成jwt的工具類,有特定的算法,和我們的那個uuid的算法不同,下面的就是提供的jwt工具類,它把jwt常用的方法非封裝成了工具類
首先我們要引入jwt的依賴
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version>
</dependency>
我們的這個jwt算法生成工具類的話,可以指定生成算法
其中jwt是由這三部分組成的
分別是? Header(頭) Payload(有效載荷) Signature(簽名)
有效載荷里面可以存儲一些自定義信息,我們可以把想要的信息通過jwt工具類加密,變成有效載荷
簽名可以防止Token被修改,簽名里面有指定我們需要的加密算法,這樣子我們拿到后端解析的時候,簽名可以解析出對應的算法,然后用對應的算法把我們的token以及token里面的信息成功解析出來
你看下面我們用工具類造token的時候有三個邏輯
?添加信息
添加過期時間
指定我們的加密算法
所以我們就不需要按照我一開始的邏輯那樣用Redis來設置我們的過期時間了
因為我們的過期時間的設置可以存到我們的有效載荷里面,然后我們后端的jwt工具類解析token,就可以知道這個token過期沒有了,就不用存到我們的Redis里面了
?所以jwt只是一種現在主流的token的實現方式,不過他確實簡便然后復雜程度也比我舉例子的那個uuid高,所以我們以后用jwt就行了,不用UUID。
但是有一個應用場景,會讓我們的jwt的使用出問題,就是我們更新密碼的時候,按理來說我們會生成新的token,但是我們舊的token不能自動過期
所以我們要結合redis,把token存到我們的redis中,如果我們修改了密碼,我們就手動讓舊的token過期,然后讓新的token存到redis里面然后生效。
其實我覺得既然要結合redis,那么我們的token沒必要在弄的時候就設置過期事件,直接用redis設置過期時間其實也是一種思路,不過其實都一樣,redis在這起到的作用就是在更新密碼的時候主動過期我們的token。