JWT的定義:
JWT是一種用於雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規范。JWT作為一個開放的標准(RFC 7519),定義了一種簡潔的,自包含的方法用於通信雙方之間以Json對象的形式安全的傳遞信息。因為數字簽名的存在,這些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘鑰對進行簽名。
JWT特點:
簡潔(Compact): 可以通過URL,POST參數或者在HTTP header發送,因為數據量小,傳輸速度也很快
自包含(Self-contained):負載中包含了所有用戶所需要的信息,避免了多次查詢數據庫
JWT結構:
JWT主要包含Header 頭部 Payload 負載 Signature 簽名,順序是 header.payload.signature 三部分之間用英語句號’.'隔開

Header頭部
頭部包含了兩部分,token 類型(“JWT”)和采用的加密算法(HMAC SHA256或者RSA等等)
例如:

然后,用Base64對這個JSON編碼就得到JWT的第一部分
Payload負載
這部分就是我們存放信息的地方了,你可以把用戶 ID 等信息放在這里,JWT 規范里面對這部分有進行了比較詳細的介紹,常用的由 iss(簽發者),exp(過期時間),sub(面向的用戶),aud(接收方),iat(簽發時間)。

同樣的,它會使用 Base64 編碼組成 JWT 結構的第二部分。
Signature簽名
前面兩部分都是使用 Base64 進行編碼的,即前端可以解開知道里面的信息。Signature 需要使用Base64編碼后的 header 和 payload 以及我們提供的一個密鑰,然后使用 header 中指定的簽名算法(HS256)進行簽名。簽名的作用是保證 JWT 沒有被篡改過。三個部分通過.連接在一起就是我們的 JWT 了,它可能長這個樣子,長度貌似和你的加密算法和私鑰有關系。
eyJhbGciOiJIUzI1NiIsIlR5cGUiOiJKd3QiLCJ0eXAiOiJKV1QifQ.eyJsb2dpblRpbWUiOiIyMDIxLTEwLTI3VDE1OjIxOjU4LjU3OCIsInVzZXJOYW1lIjoi5rGf5Y2XIiwiZXhwIjoxNjM1MzIxMTE4fQ.lUojZpIGx0a65s5FrgYlQio0vf3jOuqWOTP-DUjzGh0
JSON Web Tokens是如何工作的?
一般是在請求頭里加入Authorization,並加上Bearer標注:
fetch('api/user/1', {
headers: {
'Authorization': 'Bearer ' + token
}
})
服務端會驗證token,如果驗證通過就會返回相應的資源。整個流程就是這樣的:

優點
- 因為json的通用性,所以JWT是可以進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
- 因為有了payload部分,所以JWT可以在自身存儲一些其他業務邏輯所必要的非敏感信息。
- 便於傳輸,jwt的構成非常簡單,字節占用很小,所以它是非常便於傳輸的。
- 它不需要在服務端保存會話信息, 所以它易於應用的擴展
安全相關
- 不應該在jwt的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。
- 保護好secret私鑰,該私鑰非常重要。
- 如果可以,請使用https協議
最后附上Token工具類
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class TokenUtil {
/**
* token過期時間
*/
private static final long EXPIRE_TIME = 30 * 60 * 1000;
/**
* token秘鑰
*/
private static final String TOKEN_SECRET = "secret";
/**
* 生成token,30分鍾過期
*
* @param userName 用戶名
* @param loginTime 登錄時間
* @return 生成的token
*/
public static String sign(String userName, LocalDateTime loginTime) {
try {
// 設置過期時間
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
System.out.println(date);
// 私鑰和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 設置頭部信息
Map<String, Object> header = new HashMap<>(3);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
// 設置token中需要加載的用戶信息 存儲自己想要留給前端的內容
.withClaim("userName", userName)
.withClaim("loginTime", loginTime.toString())
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 檢驗token是否正確
*/
public static boolean verify(String token) {
try {
//設置簽名的加密算法:HMAC256
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
verifier.verify(token);
return true;
} catch (Exception e) {
return false;
}
}
/**
* 獲取token中信息 userName
*/
public static String getUsername(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("userName").asString();
} catch (JWTDecodeException e) {
e.printStackTrace();
}
return null;
}
}
