Java如何使用JWT實(shí)現(xiàn)Token認(rèn)證機(jī)制
1、JWT 的簡(jiǎn)述
JWT(JSON Web Token)是一種用于在網(wǎng)絡(luò)上安全地傳輸信息的簡(jiǎn)潔的、URL 安全的表示方法,它定義了一個(gè)緊湊且自包含的方式,用于不同實(shí)體之間安全地傳輸信息(JSON格式)。以下是關(guān)于 JWT 的詳細(xì)介紹:
1.1 JWT 的組成
JWT 通常由三部分組成,分別是 Header(頭部)、Payload(有效載荷)和 Signature(簽名)。
Header(頭部):頭部通常包含兩部分信息,即聲明類型和聲明所使用的算法。聲明類型通常是 JWT,而聲明所使用的算法則可以是 HMACSHA256、RSA 等。頭部信息會(huì)進(jìn)行 Base64URL 編碼,形成 JWT 的第一部分。
Payload(有效載荷):有效載荷包含了具體的用戶信息,如用戶ID、用戶名、角色等,也可以包含自定義的其他信息。這些信息以 JSON 格式進(jìn)行編碼,并且同樣經(jīng)過(guò) Base64URL 編碼,形成 JWT 的第二部分。Payload 中的聲明可以分為三類:Reserved claims(標(biāo)準(zhǔn)聲明)、Private claims(私有聲明)和Public claims(公共聲明)。
Signature(簽名):簽名是 JWT 的第三部分,它使用 Header 和 Payload 中的數(shù)據(jù)以及一個(gè)密鑰來(lái)生成。簽名的目的是保證消息沒(méi)有被篡改,并且只能被服務(wù)器端識(shí)別和驗(yàn)證。簽名也是通過(guò)特定的算法(如HMACSHA256)生成的,并會(huì)附加到JWT的末尾。
1.2 JWT 的工作原理
在用戶登錄后,系統(tǒng)會(huì)生成一個(gè) JWT 返回給用戶。用戶的每次請(qǐng)求都會(huì)攜帶這個(gè) JWT,通常將其放在 HTTP 請(qǐng)求的頭部(如Authorization頭部,使用Bearer模式)。服務(wù)器在接收到請(qǐng)求后,會(huì)驗(yàn)證 JWT 的簽名以確認(rèn)其完整性和來(lái)源,并根據(jù) JWT 中的信息來(lái)認(rèn)證用戶或授權(quán)用戶對(duì)資源的訪問(wèn)。
1.3 JWT 的優(yōu)點(diǎn)
簡(jiǎn)潔和緊湊:JWT 是一個(gè)字符串,不占空間,傳輸速度快。
自包含:JWT 包含了用戶信息和簽名,服務(wù)器端不需要再查詢數(shù)據(jù)庫(kù)或其他存儲(chǔ)來(lái)獲取用戶信息,實(shí)現(xiàn)了去中心化的驗(yàn)證。
跨語(yǔ)言支持:由于 JWT 是基于標(biāo)準(zhǔn)的 JSON 格式和 Base64URL 編碼實(shí)現(xiàn)的,因此它可以在不同的平臺(tái)和語(yǔ)言之間進(jìn)行傳輸和解析。
安全性:在生成 JWT 簽名時(shí)使用了加密算法,保證了 JWT 數(shù)據(jù)的安全性和完整性。然而,需要注意的是,JWT 本身不提供端到端的加密,因此不應(yīng)存儲(chǔ)敏感信息(如密碼)。為了提高安全性,可以使用 JSON Web Encryption(JWE)對(duì) JWT 進(jìn)行加密。
1.4 JWT 的應(yīng)用場(chǎng)景
JWT 廣泛應(yīng)用于現(xiàn)代 Web 應(yīng)用程序中,特別是在身份驗(yàn)證和授權(quán)方面。以下是一些常見(jiàn)的應(yīng)用場(chǎng)景:
單點(diǎn)登錄:JWT 可以用于實(shí)現(xiàn)單點(diǎn)登錄功能,用戶只需登錄一次即可在不同的系統(tǒng)或應(yīng)用之間無(wú)縫切換。
跨域身份驗(yàn)證:JWT 可以在不同的域或子域之間傳輸用戶身份信息,實(shí)現(xiàn)跨域的身份驗(yàn)證。
API安全認(rèn)證:JWT 可以用于 API 的安全認(rèn)證,確保只有合法的用戶才能訪問(wèn)受保護(hù)的資源。
1.5 JWT 的安全性注意事項(xiàng)
盡管 JWT 提供了一些安全性,但其安全性也取決于如何使用和實(shí)現(xiàn)它。以下是一些關(guān)于 JWT 安全性的注意事項(xiàng):
始終使用 HTTPS 協(xié)議:為了確保 JWT 在傳輸過(guò)程中的安全性,應(yīng)始終使用 HTTPS 協(xié)議來(lái)傳輸 JWT。這有助于防止中間人攻擊和竊聽(tīng)。
正確存儲(chǔ) JWT:在客戶端,最常見(jiàn)的 JWT 存儲(chǔ)方法是使用 cookie 或 localStorage。cookie 相對(duì)更安全,尤其是使用 HttpOnly 和 Secure 標(biāo)志時(shí)。HttpOnly 標(biāo)志可以防止 JavaScript 訪問(wèn) cookie,降低了跨站腳本(XSS)攻擊的風(fēng)險(xiǎn);而 Secure 標(biāo)志則確保 cookie 僅通過(guò) HTTPS 傳輸,降低了中間人攻擊的風(fēng)險(xiǎn)。
設(shè)置合理的有效期:JWT 的有效期應(yīng)盡可能短,以減少攻擊者利用竊取的令牌的時(shí)間。通常,JWT 應(yīng)具有較短的生存時(shí)間(如15分鐘),并使用刷新令牌在需要時(shí)更新。
避免在 JWT 中存儲(chǔ)敏感信息:由于 JWT 在客戶端和服務(wù)器之間傳輸時(shí)可能會(huì)被攔截或篡改,因此應(yīng)避免在 JWT 中存儲(chǔ)敏感信息(如密碼)。如果需要傳輸敏感信息,請(qǐng)使用加密方法(如JWE)對(duì)JWT進(jìn)行加密。
2、JWT 實(shí)現(xiàn) Token 認(rèn)證機(jī)制
【示例】使用 JWT 生成 Token 與 驗(yàn)證 Token。
(1)添加 Maven 依賴
在項(xiàng)目的 pom.xml 配置文件中添加 JWT 依賴。
<!-- JWT 依賴 --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.4.0</version> </dependency>
(2)創(chuàng)建工具類
在 util 目錄下,創(chuàng)建 JwtUtil 類(JWT 工具類)。
package com.pjb.util; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.AlgorithmMismatchException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.exceptions.TokenExpiredException; import com.auth0.jwt.interfaces.DecodedJWT; import java.util.Calendar; import java.util.HashMap; import java.util.Map; /** * JWT 工具類 * @author pan_junbiao **/ public class JwtUtil { //密鑰 private final static String SECRET_KEY = "123456789"; /** * 創(chuàng)建 JWT 令牌 */ public static String createToken(Map<String, Object> payloadClaims) { //創(chuàng)建 Header(頭部)內(nèi)容 HashMap<String, Object> headerMap = new HashMap<>(); //令牌過(guò)期時(shí)間 Calendar instance = Calendar.getInstance(); instance.add(Calendar.SECOND, 60); //60秒 //生成 JWT 令牌 String token = JWT.create() .withExpiresAt(instance.getTime()) //設(shè)置令牌過(guò)期時(shí)間 .withHeader(headerMap) //設(shè)置 Header(頭部) .withPayload(payloadClaims) //設(shè)置 Payload(載荷) .sign(Algorithm.HMAC256(SECRET_KEY)); //設(shè)置 Signature(簽名) //返回結(jié)果 return token; } /** * 驗(yàn)證 JWT 令牌 */ public static DecodedJWT verifierToken(String jwtToken) { try { //創(chuàng)建驗(yàn)證對(duì)象 JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build(); //驗(yàn)證令牌 DecodedJWT decodedJWT = jwtVerifier.verify(jwtToken); //返回結(jié)果 return decodedJWT; } catch (SignatureVerificationException ex) { System.out.println("無(wú)效的簽名"); ex.printStackTrace(); } catch (TokenExpiredException ex) { System.out.println("Token已過(guò)期"); ex.printStackTrace(); } catch (AlgorithmMismatchException ex) { System.out.println("驗(yàn)證的算法不一致"); ex.printStackTrace(); } catch (Exception ex) { System.out.println("Token驗(yàn)證發(fā)生異常"); ex.printStackTrace(); } return null; } }
(3)執(zhí)行方法
使用 JWT 生成 Token 與 驗(yàn)證 Token。
/** * 使用 JWT 實(shí)現(xiàn) Token 認(rèn)證機(jī)制 */ @Test public void testJwtToken() { //創(chuàng)建數(shù)據(jù)(Payload 載荷) Map<String, Object> payloadClaims = new HashMap<>(); payloadClaims.put("userId",1); payloadClaims.put("userName","pan_junbiao的博客"); payloadClaims.put("blogInfo","您好,歡迎訪問(wèn) pan_junbiao的博客"); payloadClaims.put("blogUrl","https://blog.csdn.net/pan_junbiao"); // 1、創(chuàng)建 JWT 令牌 String token = JwtUtil.createToken(payloadClaims); // 2、驗(yàn)證 JWT 令牌 DecodedJWT decodedJWT = JwtUtil.verifierToken(token); if(decodedJWT == null) { System.out.println("驗(yàn)證 JWT 令牌失敗"); return; } //打印結(jié)果 System.out.println("生成Token:" + token); System.out.println("驗(yàn)證Token:" + (decodedJWT != null)); System.out.println("Token過(guò)期時(shí)間:" + decodedJWT.getExpiresAtAsInstant()); System.out.println("用戶編號(hào):" + decodedJWT.getClaim("userId").asInt()); System.out.println("用戶名稱:" + decodedJWT.getClaim("userName").asString()); System.out.println("博客信息:" + decodedJWT.getClaim("blogInfo").asString()); System.out.println("博客地址:" + decodedJWT.getClaim("blogUrl").asString()); }
執(zhí)行結(jié)果:
以上就是Java如何使用JWT實(shí)現(xiàn)Token認(rèn)證機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于Java JWT實(shí)現(xiàn)Token認(rèn)證的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java基礎(chǔ)知識(shí)精通數(shù)組的使用
數(shù)組對(duì)于每一門編程語(yǔ)言來(lái)說(shuō)都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語(yǔ)言對(duì)數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java?語(yǔ)言中提供的數(shù)組是用來(lái)存儲(chǔ)固定大小的同類型元素2022-04-04springboot接受前端請(qǐng)求的方法實(shí)現(xiàn)
本文主要介紹了springboot接受前端請(qǐng)求的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01SpringBoot如何實(shí)現(xiàn)接口版本控制
這篇文章主要介紹了SpringBoot如何實(shí)現(xiàn)接口版本控制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10java中的instanceof關(guān)鍵字詳細(xì)解讀
這篇文章主要介紹了java中的instanceof關(guān)鍵字詳細(xì)解讀,instanceof 是 Java 的保留關(guān)鍵字,它的作用是測(cè)試它左邊的對(duì)象是否是它右邊的類的實(shí)例,返回 boolean 的數(shù)據(jù)類型,需要的朋友可以參考下2024-01-01SpringBoot訪問(wèn)MongoDB數(shù)據(jù)庫(kù)的兩種方式
MongoDB是一種非關(guān)系型數(shù)據(jù)庫(kù),通過(guò)文檔存儲(chǔ)數(shù)據(jù),適用于大規(guī)模數(shù)據(jù)存儲(chǔ)和高并發(fā)訪問(wèn),這篇文章主要介紹了SpringBoot訪問(wèn)MongoDB數(shù)據(jù)庫(kù)的兩種方式,感興趣想要詳細(xì)了解可以參考下文2023-05-05基于Javamail實(shí)現(xiàn)發(fā)送郵件(QQ/網(wǎng)易郵件服務(wù)器)
這篇文章主要介紹了基于Javamail實(shí)現(xiàn)發(fā)送郵件,分別使用QQ郵箱作為smtp郵件服務(wù)器發(fā)送郵件,使用網(wǎng)易郵箱作為smtp郵件服務(wù)器發(fā)送郵件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08