Java中JWT的使用的詳細(xì)教程
JWT簡介
JWT全稱為Json Web Token
JWT的本質(zhì)就是一個字符串,它是將用戶信息保存到一個Json字符串中,然后進(jìn)行編碼后得到一個JWT token,并且這個JWT token帶有簽名信息,接收后可以校驗(yàn)是否被篡改,所以可以用于在各方之間安全地將信息作為Json對象傳輸。
JWT的認(rèn)證流程如下:
1 首先,前端通過Web表單將自己的用戶名和密碼發(fā)送到后端的接口,這個過程一般是一個POST請求。建議的方式是通過SSL加密的傳輸(HTTPS),從而避免敏感信息被嗅探
2 后端核對用戶名和密碼成功后,將包含用戶信息的數(shù)據(jù)作為JWT的Payload,將其與JWT Header分別進(jìn)行Base64編碼后拼接簽名,形成一個JWT Token,形成的JWT Token就是一個如同lll.zzz.xxx的字符串
3 后端將JWT Token字符串作為登錄成功的結(jié)果返回給前端。前端可以將返回的結(jié)果保存在瀏覽器中,退出登錄時刪除保存的JWT Token即可
4 前端在每次請求時將JWT Token放入HTTP請求頭中的Authorization屬性中(解決XSS和XSRF問題)
5 后端檢查前端傳過來的JWT Token,驗(yàn)證其有效性,比如檢查簽名是否正確、是否過期、token的接收方是否是自己等等
6 驗(yàn)證通過后,后端解析出JWT Token中包含的用戶信息,進(jìn)行其他邏輯操作(一般是根據(jù)用戶信息得到權(quán)限等),返回結(jié)果
JWT結(jié)構(gòu)
JWT由3部分組成:標(biāo)頭(header)、有效載荷(payLoad)、簽名(signature)。
在傳輸?shù)臅r候,會將JWT的3部分分別進(jìn)行Base64編碼后用.
連接形成最終傳輸?shù)淖址?/p>
Header
JWT頭是一個描述JWT元數(shù)據(jù)的JSON對象,alg屬性表示簽名使用的算法,默認(rèn)為HMAC SHA256(寫為HS256);typ屬性表示令牌的類型,JWT令牌統(tǒng)一寫為JWT。最后,使用Base64 URL算法將上述JSON對象轉(zhuǎn)換為字符串保存
{ "alg": "HS256", "typ": "JWT" }
PayLoad
有效載荷部分,是JWT的主體內(nèi)容部分,也是一個JSON對象,包含需要傳遞的數(shù)據(jù)。 JWT指定七個默認(rèn)字段供選擇
iss:發(fā)行人 exp:到期時間 sub:主題 aud:用戶 nbf:在此之前不可用 iat:發(fā)布時間 jti:JWT ID用于標(biāo)識該JWT
除以上默認(rèn)字段外,我們還可以自定義私有字段,一般會把包含用戶信息的數(shù)據(jù)放到payload中,如下
{ "id": "123", "name": "cheng" }
Signature
簽名哈希部分是對上面兩部分?jǐn)?shù)據(jù)簽名,需要使用base64編碼后的header和payload數(shù)據(jù),通過指定的算法生成哈希,以確保數(shù)據(jù)不會被篡改。首先,需要指定一個密鑰(secret)。該密碼僅僅為保存在服務(wù)器中,并且不能向用戶公開。然后,使用header中指定的簽名算法(默認(rèn)情況下為HMAC SHA256)根據(jù)以下公式生成簽名
HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
在計(jì)算出簽名哈希后,JWT頭,有效載荷和簽名哈希的三個部分組合成一個字符串,每個部分用.分隔,就構(gòu)成整個JWT對象
注意JWT每部分的作用,在服務(wù)端接收到客戶端發(fā)送過來的JWT token之后:
header和payload可以直接利用base64解碼出原文,從header中獲取哈希簽名的算法,從payload中獲取有效數(shù)據(jù)
signature由于使用了不可逆的加密算法,無法解碼出原文,它的作用是校驗(yàn)token有沒有被篡改。服務(wù)端獲取header中的加密算法之后,利用該算法加上secretKey對header、payload進(jìn)行加密,比對加密后的數(shù)據(jù)和客戶端發(fā)送過來的是否一致。
為了完成簽名,除了用到header信息和payload信息外,還需要算法的密鑰,也就是secretKey。加密的算法一般有2類:
- 對稱加密:secretKey指加密密鑰,可以生成簽名與驗(yàn)簽
- 非對稱加密:secretKey指私鑰,只用來生成簽名,不能用來驗(yàn)簽(驗(yàn)簽用的是公鑰)
JWT的密鑰或者密鑰對,一般統(tǒng)一稱為JSON Web Key,也就是JWK
到目前為止,jwt的簽名算法有三種: - HMAC【哈希消息驗(yàn)證碼(對稱)】:HS256/HS384/HS512
- RSASSA【RSA簽名算法(非對稱)】(RS256/RS384/RS512)
- ECDSA【橢圓曲線數(shù)據(jù)簽名算法(非對稱)】(ES256/ES384/ES512)
Java中使用JWT
我這里用的是java-jwt
引入依賴
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency>
對稱簽名
生成JWT的Token
/** * 生成JWT token */ @Test void generateToken(){ //預(yù)設(shè)一個token過期時間 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.HOUR,1);//過期時間為1小時 String token = JWT.create() .withHeader(new HashMap<>())//Header .withClaim("userId", 123)//PayLoad .withClaim("userName", "程") .withClaim("userId1", "456") .withExpiresAt(calendar.getTime())//過期時間 .sign(Algorithm.HMAC256("12345"));//簽名用的密鑰secret System.out.println(token); }
利用base64解密工具來查看生成的JWT Token中header和payLoad的明文
解析JWT字符串
/** * 解析jwt字符串 */ @Test void resolveToken(){ String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWRJbnQiOjEyMywidXNlcklkU3RyaW5nIjoiNDU2IiwidXNlck5hbWUiOiLnqIsiLCJleHAiOjE2NzU5MTQzMDZ9.MNC-YCxt8C0t9SNbj3_XMRknkK3-PKBP5xX6_JLB8y8"; //創(chuàng)建解析對象,使用的算法和secret要和創(chuàng)建token時保持一致 JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("12345")).build(); DecodedJWT decodedJWT = jwtVerifier.verify(token); System.out.println(decodedJWT.getPayload());//base64編碼的payLoad Claim userIdInt = decodedJWT.getClaim("userIdInt"); Claim userIdString = decodedJWT.getClaim("userIdString"); Claim userName = decodedJWT.getClaim("userName"); System.out.println("userIdInt:"+userIdInt.asInt()); System.out.println("userIdString:"+userIdString.asString()); System.out.println("userName:"+userName.asString()); System.out.println("過期時間:"+new LocalDateTime(decodedJWT.getExpiresAt())); }
如果我們設(shè)置的token時間短,比如設(shè)置為1秒
那么解析時為拋出如下異常
非對稱簽名
private static final String RSA_PRIVATE_KEY = "..."; private static final String RSA_PUBLIC_KEY = "..."; /** * 生成token * @param payload token攜帶的信息 * @return token字符串 */ public static String getTokenRsa(Map<String,String> payload){ // 指定token過期時間為7天 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, 7); JWTCreator.Builder builder = JWT.create(); // 構(gòu)建payload payload.forEach((k,v) -> builder.withClaim(k,v)); // 利用hutool創(chuàng)建RSA RSA rsa = new RSA(RSA_PRIVATE_KEY, null); // 獲取私鑰 RSAPrivateKey privateKey = (RSAPrivateKey) rsa.getPrivateKey(); // 簽名時傳入私鑰 String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null, privateKey)); return token; } /** * 解析token * @param token token字符串 * @return 解析后的token */ public static DecodedJWT decodeRsa(String token){ // 利用hutool創(chuàng)建RSA RSA rsa = new RSA(null, RSA_PUBLIC_KEY); // 獲取RSA公鑰 RSAPublicKey publicKey = (RSAPublicKey) rsa.getPublicKey(); // 驗(yàn)簽時傳入公鑰 JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey, null)).build(); DecodedJWT decodedJWT = jwtVerifier.verify(token); return decodedJWT; }
到此這篇關(guān)于Java中JWT的使用的文章就介紹到這了,更多相關(guān)Java中JWT使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)開根號的運(yùn)算方式
這篇文章主要介紹了java實(shí)現(xiàn)開根號的運(yùn)算方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07Maven在Windows中的配置以及IDE中的項(xiàng)目創(chuàng)建(圖文教程)
這篇文章主要介紹了Maven在Windows中的配置以及IDE中的項(xiàng)目創(chuàng)建(圖文教程),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09SpringBoot如何讀取application.properties配置文件
這篇文章主要介紹了SpringBoot如何讀取application.properties配置文件問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05SpringMVC中MultipartFile上傳獲取圖片的寬度和高度詳解
本篇文章主要介紹了SpringMVC中MultipartFile上傳獲取圖片的寬度和高度,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05簡單的理解java集合中的HashSet和HashTree幾個重寫方法
這篇文章主要介紹了簡單的理解java集合中的HashSet和HashTree幾個重寫方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Springboot如何實(shí)現(xiàn)代理服務(wù)器
這篇文章主要介紹了Springboot如何實(shí)現(xiàn)代理服務(wù)器問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06spring boot整合RabbitMQ實(shí)例詳解(Fanout模式)
這篇文章主要介紹了spring boot整合RabbitMQ的實(shí)例講解(Fanout模式),非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04java實(shí)現(xiàn)客戶端向服務(wù)器發(fā)送文件
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)客戶端向服務(wù)器發(fā)送文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01