簡介
JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且自包含的方式,用于將資訊作為JSON物件在各方之間安全地傳輸,可以對該資訊進行驗證和信任,因為它是數字簽名的,JWT可以使用密鑰(使用HMAC演算法)或使用RSA或ECDSA的公鑰/私鑰對進行簽名,
JWT優點
-
簡潔(Compact):可以通過URL、POST引數或在HTTP標頭內發送,由于它的大小,它的傳輸速度也很快,
-
自包含(Self-contained):有效負載包含有關用戶的所有必需資訊,可以避免多次查詢資料庫,
-
JWT是跨語言的,
-
不需要在服務端保存會話資訊,特別適用于分布式微服務,
JWT使用場景
1.授權
這是JWT的典型使用場景,一旦用戶登錄,每個后續請求都將包含JWT,允許用戶訪問該令牌允許的路由、服務和資源,單點登錄是現在廣泛使用JWT的一個特性,因為它的開銷很小,并且能夠在不同域的系統之間輕松使用,
具體流程如下圖:

a.用戶通過登錄將用戶名和密碼發送給服務端,
b.服務端驗證用戶名和密碼,驗證通過則生成JWT,將生成的JWT回傳給客戶端,
c.客戶端收到JWT后,將它保存在本地,當退出登錄時再清除保存的JWT,
d.當客戶端訪問服務端受保護的資源時,需要帶上JWT,一般將JWT放入HTTP Header的Authorization標頭中(使用Bearer模式),
e.服務端接收到請求時,首先會驗證JWT的有效性,驗證通過則正常執行對應邏輯回傳對應資源,驗證失敗則拒絕訪問對應資源,
2.資訊交換
JWT是在各方之間安全傳輸資訊的好方法,因為JWT可以被簽名(例如:使用公鑰/私鑰對),您可以確定發送者就是他們所說的那個人,此外,由于使用標頭和有效負載計算簽名,因此還可以驗證內容是否被篡改,
JWT結構
JWT由用點(.)分隔的以下三個部分組成:
-
標頭(Header)
-
有效載荷(Payload)
-
簽名(Signature)
因此,JWT通常如下所示:
Header.Payload.Signature
標頭(Header)
Header通常由兩部分組成:令牌的型別,即JWT,以及簽名演算法,如HMAC SHA256或RSA,如下所示:
{
"alg": "HS256",
"typ": "JWT"
}
這個JSON將被Base64編碼,組成JWT的第一部分,
有效載荷(Payload)
Payload包含有關物體和其他資料的宣告,如下所示:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
同樣這個JSON將被base64編碼,組成JWT的第二部分,
關于Payload應該注意兩點,由于只是使用Base64編碼并沒有加密,所以不應該存盤敏感資料,其次是應該設定到期時間,
簽名(Signature)
Signature需要使用編碼后的header和Payload以及我們提供的一個密鑰,然后使用header中指定的簽名演算法進行簽名,該簽名字串將作為JWT中的第三部分,如下所示:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Java中使用JWT
maven依賴:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.16.0</version>
</dependency>
JwtUtils:
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.Map;
public class JwtUtils {
//加密密鑰
private static final String SECRET = "5b6u5L+h5YWs5LyX5Y+377ya5oiR55yf55qE5LiN5LyaSmF2YeWVig==";
//Token過期時間
private static final int EXP_TIME_MINUTE = 30;
/**
* 創建Token
* @param payloadDataMap
* @return
*/
public static String createToken(Map<String, String> payloadDataMap) {
JWTCreator.Builder builder = JWT.create();
//設定自定義的資料
payloadDataMap.forEach((key, value) -> builder.withClaim(key, value));
//設定token有效期 60s
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, EXP_TIME_MINUTE);
builder.withExpiresAt(calendar.getTime());
//生成Token
return builder.sign(Algorithm.HMAC256(SECRET));
}
/**
* 驗證Token
* @param token
* @return
*/
public static DecodedJWT verifyToken(String token) {
return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
}
}
創建Token:
@Test
public void testCreateToken(){
Map<String, String> dataMap = new HashMap<>();
dataMap.put("id", "7");
dataMap.put("username", "buhe");
dataMap.put("wechat", "tryjava");
System.out.println(JwtUtils.createToken(dataMap));
}
輸出:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3ZWNoYXQiOiJ0cnlqYXZhIiwiaWQiOiI3IiwiZXhwIjoxNjI0ODY2MTE2LCJ1c2VybmFtZSI6ImJ1aGUifQ._hELqy_DpBL4IlE5N-ZtUNFia72MOxHK220ISuzSfKE
驗證Token,并輸出Payload中的資料:
@Test
public void testVerifyToken(){
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ3ZWNoYXQiOiJ0cnlqYXZhIiwiaWQiOiI3IiwiZXhwIjoxNjI0ODY2MTE2LCJ1c2VybmFtZSI6ImJ1aGUifQ._hELqy_DpBL4IlE5N-ZtUNFia72MOxHK220ISuzSfKE";
DecodedJWT decodedJWT = JwtUtils.verifyToken(token);
decodedJWT.getClaims().forEach((key, value) -> System.out.println(key + " : " + value));
}
輸出:
wechat : "tryjava"
id : "7"
exp : 1624866116
username : "buhe"
驗證失敗的情況
token驗證成功時會回傳DecodedJWT物件,從DecodedJWT中,我們能獲取到Token相關的一些資訊,token驗證失敗時則會拋出對應例外,
token驗證例外分類如下圖:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/288627.html
標籤:其他
