該文主要帶你瞭解什麼是 JWT,以及JWT 定義和先關概念的介紹,並經過簡單Demo 帶你瞭解如何使用 SpringBoot 2 整合 JWT。
介紹前在這裏咱們來探討一下如何學習一門新的技術,我我的總結爲 RSA。javascript
關於 RSA 僅僅代碼我的的學習觀點,只是給讀者一個不成熟的小建議哈
官網介紹以下:html
What is JSON Web Token?
JSON Web Token (JWT) is an open standard ( RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.
中文翻譯:
JSON Web令牌(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用於在各方之間做爲JSON對象安全地傳輸信息。該信息能夠被驗證和信任,由於它是數字簽名的。JWTS可使用祕密(使用HMAC算法)或公鑰/私鑰對使用RSA或ECDSA來簽名。
雖然JWTS能夠加密,但也提供保密各方之間,咱們將重點放在簽名令牌。簽名的令牌能夠驗證包含在其中的聲明的完整性,而加密的令牌隱藏這些聲明以防其餘各方。當令牌使用公鑰/私鑰對簽名時,簽名也證實只有持有私鑰的方纔是簽名的方。java
使用 JWT 前須要先了解三塊內容:git
頭部信息由2部分組成github
頭部信息 JSON 代碼以下:算法
{ "alg": "HS256", "typ": "JWT" }
而後,這個JSON被編碼爲 Base64Url,造成 JWT 的第一部分。spring
其中包含聲明(claims),聲明能夠存放實體(一般是用戶)和其餘數據的聲明,聲明包括3種類型segmentfault
已註冊聲明
這些是一組預約義聲明,不是強制性的,但建議使用,以提供一組有用的,可互操做的聲明。其中一些是: iss(發行人), exp(到期時間),sub(主題), aud(觀衆)等安全
公開聲明
能夠參考 IANA JSON Web令牌註冊表https://www.iana.org/assignme... 查看公共的聲明springboot
私有聲明
根據根據本身的業務須要自定義的一些數據格式。
示例有效負載能夠是:
{ "sub": "1234567890", "name": "John Doe", "admin": true }
這個部分須要 base64 加密後的 頭部信息(header) 和 base64 加密後的載荷信息(payload),使用鏈接組成的字符串,而後經過頭部信息(header)中聲明的加密方式進行加鹽 secret 組合在加密,而後就構成了 JWT 的第三部分。
例如,若是要使用HMAC SHA256算法,將按如下方式建立簽名:
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
首先去 JWT 官網一探究竟,訪問 https://jwt.io 進入 JWT 官網。接下來咱們開始學習若是使用JWT,經過點擊上圖中 LEARN MORE ABOUT JWT 顯示以下圖:而後點擊START USING THE TOOL。
![圖片]
![圖片]
以下圖所示 選擇對應的語言的 JWT 使用教程。咱們這裏介紹是是 標註有:maven:com.auth0 java-jwt 的版本。
查看 JWT GitHub 示例教程和源碼。 https://github.com/auth0/java-jwt
在README.md 文件中有使用介紹和示例程序。
GitHub 上的示例相對簡單些,接下來我帶你們寫一個相對詳細的Demo。
第一步在SpringBoot 應用中引入JWT 依賴到pom.xml中
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.1</version> </dependency>
咱們經過三個方法來演示如何使用JWT
第一步:構建頭部信息
Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT");
第二步:構建密鑰信息
Algorithm algorithm = Algorithm.HMAC256("secret");
第三步:咱們經過定義註冊和自定義聲明 並組合頭部信息和密鑰信息生成jwt token
String token = JWT.create() .withHeader(map)// 設置頭部信息 Header .withIssuer("SERVICE")//設置 載荷 簽名是有誰生成 例如 服務器 .withSubject("this is test token")//設置 載荷 簽名的主題 // .withNotBefore(new Date())//設置 載荷 定義在什麼時間以前,該jwt都是不可用的. .withAudience("APP")//設置 載荷 簽名的觀衆 也能夠理解誰接受簽名的 .withIssuedAt(nowDate) //設置 載荷 生成簽名的時間 .withExpiresAt(expireDate)//設置 載荷 簽名過時的時間 .sign(algorithm);//簽名 Signature
詳細代碼以下:
@Test public void createToken() { String secret = "secret";// token 密鑰 Algorithm algorithm = Algorithm.HMAC256("secret"); // 頭部信息 Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT"); Date nowDate = new Date(); Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);// 2小過時 String token = JWT.create() .withHeader(map)// 設置頭部信息 Header .withIssuer("SERVICE")//設置 載荷 簽名是有誰生成 例如 服務器 .withSubject("this is test token")//設置 載荷 簽名的主題 // .withNotBefore(new Date())//設置 載荷 定義在什麼時間以前,該jwt都是不可用的. .withAudience("APP")//設置 載荷 簽名的觀衆 也能夠理解誰接受簽名的 .withIssuedAt(nowDate) //設置 載荷 生成簽名的時間 .withExpiresAt(expireDate)//設置 載荷 簽名過時的時間 .sign(algorithm);//簽名 Signature Assert.assertTrue(token.length() > 0); }
自定義信息經過 withClaim 方法進行添加,具體操做以下:
JWT.create() .withHeader(map) .withClaim("loginName", "zhuoqianmingyue") .withClaim("userName", "張三") .withClaim("deptName", "技術部")
生成攜帶自定義信息 JWT token 詳細代碼以下:
@Test public String createTokenWithChineseClaim() { Date nowDate = new Date(); Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);// 2小過時 Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT"); Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create().withHeader(map) /* 設置 載荷 Payload */ .withClaim("loginName", "zhuoqianmingyue").withClaim("userName", "張三").withClaim("deptName", "技術部") .withIssuer("SERVICE")// 簽名是有誰生成 例如 服務器 .withSubject("this is test token")// 簽名的主題 // .withNotBefore(new Date())//定義在什麼時間以前,該jwt都是不可用的 .withAudience("APP")// 簽名的觀衆 也能夠理解誰接受簽名的 .withIssuedAt(nowDate) // 生成簽名的時間 .withExpiresAt(expireDate)// 簽名過時的時間 /* 簽名 Signature */ .sign(algorithm); Assert.assertTrue(token.length() > 0); return token;
第一步:構建密鑰信息
Algorithm algorithm = Algorithm.HMAC256("secret");
第二步:經過密鑰信息和簽名的發佈者的信息生成JWTVerifier (JWT驗證類)
JWTVerifier verifier = JWT.require(algorithm) .withIssuer("SERVICE") .build(); Algorithm algorithm = Algorithm.HMAC256("secret");
不添加 .withIssuer("SERVICE") 也是能夠獲取 JWTVerifier 。
第三步:經過JWTVerifier 的verify獲取 token中的信息。
DecodedJWT jwt = verifier.verify(token);
以下面代碼所示就能夠獲取到咱們以前生成 token 的 簽名的主題,觀衆 和自定義的聲明信息。
String subject = jwt.getSubject(); List<String> audience = jwt.getAudience(); Map<String, Claim> claims = jwt.getClaims(); for (Entry<String, Claim> entry : claims.entrySet()) { String key = entry.getKey(); Claim claim = entry.getValue(); System.out.println("key:"+key+" value:"+claim.asString()); }
驗證 JWT Token 詳細代碼以下:
@Test public void verifyToken() throws UnsupportedEncodingException { String token = createTokenWithChineseClaim2(); Algorithm algorithm = Algorithm.HMAC256("secret"); JWTVerifier verifier = JWT.require(algorithm).withIssuer("SERVICE").build(); // Reusable verifier instance DecodedJWT jwt = verifier.verify(token); String subject = jwt.getSubject(); List<String> audience = jwt.getAudience(); Map<String, Claim> claims = jwt.getClaims(); for (Entry<String, Claim> entry : claims.entrySet()) { String key = entry.getKey(); Claim claim = entry.getValue(); log.info("key:" + key + " value:" + claim.asString()); } Claim claim = claims.get("loginName"); log.info(claim.asString()); log.info(subject); log.info(audience.get(0)); } public String createTokenWithChineseClaim2() throws UnsupportedEncodingException { Date nowDate = new Date(); Date expireDate = getAfterDate(nowDate, 0, 0, 0, 2, 0, 0);// 2小過時 Map<String, Object> map = new HashMap<String, Object>(); map.put("alg", "HS256"); map.put("typ", "JWT"); User user = new User(); user.setUserNaem("張三"); user.setDeptName("技術部"); Gson gson = new Gson(); String userJson = gson.toJson(user); String userJsonBase64 = BaseEncoding.base64().encode(userJson.getBytes()); Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create().withHeader(map) .withClaim("loginName", "zhuoqianmingyue").withClaim("user", userJsonBase64).withIssuer("SERVICE")// 簽名是有誰生成 .withSubject("this is test token")// 簽名的主題 // .withNotBefore(new Date())//該jwt都是不可用的時間 .withAudience("APP")// 簽名的觀衆 也能夠理解誰接受簽名的 .withIssuedAt(nowDate) // 生成簽名的時間 .withExpiresAt(expireDate)// 簽名過時的時間 .sign(algorithm);//簽名 Signature return token; }
JWT 就是一個生成 Token 的工具,若是不使用 JWT 咱們也能夠根據本身加密規則生成 Token。只不過 JWT 規範了生成 Token 定義了一個標準而已。JWT 的核心的功能就是:生成Token、解析Token。在 玩轉 SpringBoot 2 之整合 JWT 下篇中將帶你們經過一個接口登陸的案例簡單介紹 JWT 實戰操做。
具體代碼示例請查看個人GitHub 倉庫 springbootexamples 中的 spring-boot-2.x-jwt 下 src/test/java JWTDemo.java文件。
GitHub:https://github.com/zhuoqianmi...
https://jwt.io/introduction/
https://github.com/auth0/java...