springboot中JJWT的簡單使用
一 什麼是JWT
jwt全稱json web token,是基於json協議的用於結局認證授權的方法。token就是令牌,其主要作用是用來進行授權(Authorization),授權和認證是不同的概念,認證是系統通過賬號密碼或其他手段來驗證身份,授權是在認證後獲得系統授予的權限。系統想知道用戶有什麼權限,需要給用戶貼上標籤,方式有很多種,token是其中一種。當用戶獲得token後,用戶後續的請求只需附帶token,系統便可進行授權。jwt不同與cookie-session,它不會在服務端進行儲存,token會被寫入進http請求的header或body中進行雙向的傳輸。
JWT組成
JWT由三部分組成,分別是header,playload和signature。由於本文主要寫JJWT的使用,JWT結構就不詳細展開了,對於這部分還不瞭解的可以去JWT官網上查看,連接:JWT官網介紹
- Header
- PlayLoad
- Signature
二 什麼是JJWT
JJWT旨在成爲最易於使用和理解的庫,用於在JVM和Android上創建和驗證JSON Web令牌(JWT)。 JJWT是完全基於JWT,JWS,JWE,JWK和JWA RFC規範以及Apache 2.0許可條款下的開源的純Java實現。 該圖書館由Okta的高級建築師Les Hazlewood創建,並由貢獻者社區提供支持和維護。 Okta是面向開發人員的完整身份驗證和用戶管理API。 我們還添加了一些不屬於該規範的便利擴展,例如JWS壓縮和聲明執行。
以上內容由jjwt官方文檔機翻而來
簡而言之,JJWT提供了java環境下的使用JWT的能力,使得具體實現對開發者透明,開發者只需用簡單幾行代碼即可創建或者解析一個token。
三 簡單入門
-
導入依賴(Maven環境)
<!--老版本--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency>
注意,現在jjwt已經更新到0.11.0,理論上說0.xx.x到0.xx.x的更新屬於兼容性的,但經過嘗試,發現還是有不少改動。這裏也貼出來最新的版本的Maven工程依賴
<!--新版本--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.1</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.1</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred --> <version>0.11.1</version> <scope>runtime</scope> </dependency>
-
生成token
jjwt中,使用
Jwts.builder()
進行構建token。// 假設代碼塊被包含在一個函數中 Map<String, Objcet> claims = new HashMap<>(); // claims就是playload中的內容,可以寫入自己需要的鍵值 claims.put("key", "value"); // 構建 JwtBuilder jwtBuilder = Jwts.builder() // 設置有效載荷 .setClaims(claims) // 設置subject .setSubject(subject) // 設置簽發時間 .setIssuedAt(new Date()) // 採用HS256方式簽名,key就是用來簽名的祕鑰 .signWith(SignatureAlgorithm.HS256, key); // 調用compact函數將token打包成String並返回 return jwtBuilder.compact();
在上述代碼塊中,對JWT的playload進行了設置,沒有自定義header。
這裏採用的HS256加密,HS256是一種對稱祕鑰加密手段,利用哈希MAC加密方式,即加密解密都使用相同的祕鑰"key"。也可以採用RS256加密或者其他加密方法,RS256是公開祕鑰加密,祕鑰分爲公鑰和私鑰,私鑰用於生成JWT,公鑰用於解密,想知道更具體的可以學習信息安全。但無論哪種加密方法,都得保護好祕鑰,並確保祕鑰難以被碰撞。
-
服務端發送token
在步驟2中調用
compact()
會生成一長串經過編碼的字符串,字符串格式爲xxxxxx.xxxxxxxx.xxxxxxx,三個部分分別對應頭,載荷和簽名。將token發送給客戶端往往通過httpheaders中的Authorization字段發送。當然也可以放在http數據包中發送給客戶端。// 在header中寫入Authorization @RequestMapping(value = "/jwttest1", method = RequestMethod.GET) public String test1(HttpServletRequest request, HttpServletResponse response) { // 通過步驟2中的方法獲取token String token = ... response.setHeader("Authorization", token); return "success"; }
這裏要注意,在前端如果是跨域請求,js獲取heaer中隱私的信息在規範中是不安全的,所以服務器需設置,讓這個header暴露出來
@Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowCredentials(true) .exposedHeaders("Authorization"); }
-
服務端解析token
發送token後,客戶端的請求會附帶token,token同樣可以放httpheader中或報文中,接下來需要解析token
@RequestMapping(value = "/jwttest2", method = RequestMethod.GET) public void test2(HttpServletRequest request, HttpServletResponse response) { String token = request.getHeader("Authorization"); // 調用下面寫的方法解析即可,由於沒有寫方法的類,這裏就不演示了 }
// 解析token public Claims jwtParser(String token) { Claims claims; // token不一定通過驗證,所以需要包裹try-catch捕獲jjwt提供的JwtException try { claims = Jwts.parser() // HS256是對稱加密體系,加密解密使用同一個key .setSigningKey(key) .parseClaimsJws(token) .getBody(); } catch (JwtException e) { claims = null; e.printStackTrace(); } return claims; }
獲取到的claims就是playload,如果是playload中的標準字段可以直接通過函數取出如
String subject = (String) claims.getSubject();
如果是自己自定義的鍵值可以通過
get()
方法取出,假設儲存的值可以轉換StringString value = (String) claims.get("key");
這樣就獲取到並解析了token。