JWT簡介:從Session到Token的轉變
導讀
JWT
,全稱Json Web Token
。我們平常所說的token
實際上就是說JWT
技術中的T
。
Session
和Token
的對比
如果你對jsp
和Servlet
非常熟悉,你應該對Session
非常熟悉。每當使用者登入的時候都會使用Cookie
和Session
聯動起來,服務端使用session.setAttribute()
方法完整地儲存使用者的資訊,並使用session.getAttribute()
方法完整地獲取使用者的資訊。聽起來非常方便?
可是呢,如果你讀過我之前寫的Session
工作原理,你會發現:Session
對於伺服器的壓力還是相當大的。如果專案突然迎來了海量資料和大量併發,伺服器當機的概率大大增加,對於已經落地的專案甚至會產生不可逆轉的錯誤。
於是,使用者線上時就每時每刻維護一個Session
的方法逐漸被摒棄;進而選擇了使用者每次請求的時候傳送使用者資訊,順便檢查許可權。一舉兩得,豈不美哉?JWT
就應運而生了。在分散式場景中,僅在請求時伺服器產生少許壓力的token
也就比始終給伺服器施加壓力並無法釋放的Session
更為實用。
Token
的結構
Token
本質上是一串字串,其中包含三個部分,三個部分分別是頭部、負載和簽名,每個部分由英文句號.
來分開。
為什麼這麼做?因為這個字串可以直接作為使用者的標識,一旦被其他人截獲,便能夠直接作為請求使用。所以,我們往往會將這三個部分使用Base64
演算法進行編碼,請求傳送到伺服器之後再將資訊使用Base64
演算法進行解碼。
頭部
頭部主要是包含兩段資訊:資料型別和簽名演算法。
資料型別一般是選擇JWT
作為資料型別,不同於一般的Json
又不同於普通的字串;
簽名演算法一般是選擇HS256
,這也是官方推薦的演算法。
負載
第二個部分則是負載,也作有效負載。其中包含了一些有必要的資料宣告。比如,我們可以將使用者id
和使用者許可權碼等等非常重要的資訊。
但是呢,如果你傳送的資訊真的被截獲了,還是會被很簡單的解碼獲得了資訊,所以只能在這部分只能儘可能不要放一些敏感資訊,否則會被盜號。
同樣的,這部分也會使用Base64
演算法編碼。
簽名
簽名就像是交付的時候有個安全員通過唯一指定的識別器來確認操作的使用者確實是你,而不是其他的什麼人。
所以簽名這部分就是頭部和負載的結合,再使用一個隨機鹽再次編碼。每當使用者傳送請求的時候,伺服器都會首先使用第一部分和第二部分使用只有伺服器知道的隨機鹽加密,再和第三部分比對。加密後的資訊和第三部分是相同的,那麼就是正確的,本次識別器確認了使用者資訊,否則就是非法登入。
這個演算法從邏輯上能夠在一定程度上保證請求資訊不會被其他使用者非法使用。但是呢,這個演算法還是不能夠保證別有用心的人修改你的個人隱私。這就很無奈了。
一個小例子
這個小例子雖然用到了SpringBoot
,但是隻使用了框架內的測試功能,單純地使用命令列輸出所有的結果。
由於我們並沒有用到SpringBoot
自帶的測試類,所以就只是單純地在{專案根目錄}/src/main/test/{自定義包名}
下新建JWTTest.java
,並直接使用JWT
工具類:
@Test
public void testJWT() {
// set expire time
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 90);
// create jwt
HashMap<String, Object> headers = new HashMap<>();
headers.put("type", "JSON");
String token = JWT.create()
.withHeader(headers)
.withClaim("user", "sakebow")
.withClaim("id", "20202104126")
.withExpiresAt(calendar.getTime())
.sign(Algorithm.HMAC256("~@#sakebow?!~"));
System.out.println(token);
}
這段程式碼執行之後就會生成一長串程式碼:
eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiSlNPTiIsImFsZyI6IkhTMjU2In0.eyJpZCI6IjIwMjAyMTA0MTI2IiwiZXhwIjoxNjAwNjAwNjM1LCJ1c2VyIjoic2FrZWJvdyJ9.xigradwatkwZYO1QZJ98_sa6qH9L-_8uYyi5_HUSRjE
看起來毫無章法?不過沒有關係,我們還能解碼。
@Test
public void testDecodeJWT() {
String token = "eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiSlNPTiIsImFsZyI6IkhTMjU2In0.eyJpZCI6IjIwMjAyMTA0MTI2IiwiZXhwIjoxNjAwNjAwNjM1LCJ1c2VyIjoic2FrZWJvdyJ9.xigradwatkwZYO1QZJ98_sa6qH9L-_8uYyi5_HUSRjE";
JWTVerifier jwtVerifier = JWT
.require(Algorithm.HMAC256("~@#sakebow?!~"))
.build();
DecodedJWT decodedJWT = jwtVerifier.verify(token);
System.out.println(decodedJWT.getHeader() + ", " + decodedJWT.getPayload());
}
JWTVerifier
除了解碼以外,還會核對前面兩個部分合在一起加密是否與最後一段相等。同時,JWT
還會經常變化,這也正為JWT
提供了一定的安全性。
隨機鹽
不知道你們注意到沒有,在JWT
加密中有一段程式碼:
sign(Algorithm.HMAC256("~@#sakebow?!~"));
實際上這個~@#sakebow?!~
就是我們自己規定的隨機鹽,也就是根據這個片段對我們傳送的資料進行加密。因為這個片段基本上只有開發著自己知道,所以安全性還是可以保證的。但是,安全性可不僅限於使用者自己使用。
如果說其他別有用心的使用者拿到了這個資料,偽造了其他人的資訊,傳送了非法請求,到了伺服器結果就會被當成已經授權的人,然後回應請求。這將會讓整個程式會變得非常危險。所以,這段隨機鹽決不可以儲存在客戶端。
是不是有點能理解了呢?
相關文章
- JSON Web Token(JWT) 簡介JSONWebJWT
- 【網路傳輸】Cookie、Session、Token、JWTCookieSessionJWT
- 一文搞懂Cookie,Session,Token,JWTCookieSessionJWT
- 一文搞懂 Cookie,Session,Token,JWTCookieSessionJWT
- jwt簡介JWT
- 不要用JWT替代session管理(上):全面瞭解Token,JWT,OAuth,SAML,SSOJWTSessionOAuth
- JWT TokenJWT
- Session 簡介Session
- 【轉】Session ID/session token 及和cookie區別SessionCookie
- 簡聊 Session 與 Token 身份驗證Session
- jwt生成token和token解析基礎JWT
- JWT(Json WEB Token)JWTJSONWeb
- jwt生成token報錯JWT
- token 會話設計 (JWT)會話JWT
- Jwt建立身份令牌TokenJWT
- 理解 cookie、session、tokenCookieSession
- 從提升樹到 XGBoost, 原理簡介
- jwt token 重新整理問題JWT
- Spring Boot中使用token:jwtSpring BootJWT
- 自己寫token類(無視jwt)JWT
- 從DBA到Oracle Applications DBA的轉變過程 (轉)OracleAPP
- 你在用 JWT 代替 Session?JWTSession
- SpringBoot 整合 JWT 實現 token 驗證,token 登出Spring BootJWT
- JWT 快速為使用者生成 tokenJWT
- Composer 使用 JWT 生成 TOKEN 例項JWT
- JWT Token儲存在Cookie還是LocalStorageJWTCookie
- jwt與session的登入鑑權JWTSession
- 探索從 MVC 到 MVVM + Flux 架構模式的轉變MVCMVVMUX架構模式
- 從 RGB 到 HSV 的轉換詳細介紹
- 《Qt 6.x從入門到精通》簡介QT
- 徹底理解cookie,session,tokenCookieSession
- 聊一聊JWT與sessionJWTSession
- springboot+jwt做api的token認證Spring BootJWTAPI
- ASP.NET Session簡單介紹ASP.NETSession
- 從遊戲開發到應用開發的轉變遊戲開發
- 從鍊金術到化學--遊戲設計的演變(轉)遊戲設計
- DRF之JWT簽發Token原始碼分析JWT原始碼
- Docker 從入門到實踐-1-Docker簡介Docker