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(頭部):頭部通常包含兩部分信息,即聲明類(lèi)型和聲明所使用的算法。聲明類(lèi)型通常是 JWT,而聲明所使用的算法則可以是 HMACSHA256、RSA 等。頭部信息會(huì)進(jìn)行 Base64URL 編碼,形成 JWT 的第一部分。
Payload(有效載荷):有效載荷包含了具體的用戶(hù)信息,如用戶(hù)ID、用戶(hù)名、角色等,也可以包含自定義的其他信息。這些信息以 JSON 格式進(jìn)行編碼,并且同樣經(jīng)過(guò) Base64URL 編碼,形成 JWT 的第二部分。Payload 中的聲明可以分為三類(lèi):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 的工作原理
在用戶(hù)登錄后,系統(tǒng)會(huì)生成一個(gè) JWT 返回給用戶(hù)。用戶(hù)的每次請(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)證用戶(hù)或授權(quán)用戶(hù)對(duì)資源的訪(fǎng)問(wèn)。
1.3 JWT 的優(yōu)點(diǎn)
簡(jiǎn)潔和緊湊:JWT 是一個(gè)字符串,不占空間,傳輸速度快。
自包含:JWT 包含了用戶(hù)信息和簽名,服務(wù)器端不需要再查詢(xún)數(shù)據(jù)庫(kù)或其他存儲(chǔ)來(lái)獲取用戶(hù)信息,實(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)登錄功能,用戶(hù)只需登錄一次即可在不同的系統(tǒng)或應(yīng)用之間無(wú)縫切換。
跨域身份驗(yàn)證:JWT 可以在不同的域或子域之間傳輸用戶(hù)身份信息,實(shí)現(xiàn)跨域的身份驗(yàn)證。
API安全認(rèn)證:JWT 可以用于 API 的安全認(rèn)證,確保只有合法的用戶(hù)才能訪(fǎng)問(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:在客戶(hù)端,最常見(jiàn)的 JWT 存儲(chǔ)方法是使用 cookie 或 localStorage。cookie 相對(duì)更安全,尤其是使用 HttpOnly 和 Secure 標(biāo)志時(shí)。HttpOnly 標(biāo)志可以防止 JavaScript 訪(fǎng)問(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 在客戶(hù)端和服務(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 依賴(lài)
在項(xiàng)目的 pom.xml 配置文件中添加 JWT 依賴(lài)。
<!-- JWT 依賴(lài) -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
(2)創(chuàng)建工具類(lèi)
在 util 目錄下,創(chuàng)建 JwtUtil 類(lèi)(JWT 工具類(lèi))。
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 工具類(lèi)
* @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","您好,歡迎訪(fǎng)問(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ù)編號(hào):" + decodedJWT.getClaim("userId").asInt());
System.out.println("用戶(hù)名稱(chēng):" + 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)文章
SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)
這篇文章主要介紹了如何使用SpringBoot整合Quartz,并將定時(shí)任務(wù)寫(xiě)入庫(kù)中(持久化存儲(chǔ)),還可以任意對(duì)定時(shí)任務(wù)進(jìn)行如刪除、暫停、恢復(fù)等操作,需要的可以了解下2023-09-09
JAVA過(guò)濾標(biāo)簽實(shí)現(xiàn)將html內(nèi)容轉(zhuǎn)換為文本的方法示例
這篇文章主要介紹了JAVA過(guò)濾標(biāo)簽實(shí)現(xiàn)將html內(nèi)容轉(zhuǎn)換為文本的方法,涉及java針對(duì)HTML代碼的正則替換相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
Java中單元測(cè)試框架JUnit知識(shí)點(diǎn)整理
在Java開(kāi)發(fā)中JUnit是最常用的單元測(cè)試框架之一,編寫(xiě)JUnit測(cè)試的目的是確保代碼的正確性、可維護(hù)性和可擴(kuò)展性,這篇文章主要介紹了Java中單元測(cè)試框架JUnit知識(shí)點(diǎn)整理的相關(guān)資料,需要的朋友可以參考下2025-08-08
使用Aop的方式實(shí)現(xiàn)自動(dòng)日志記錄的方式詳細(xì)介紹
這篇文章主要介紹了使用Aop的方式實(shí)現(xiàn)自動(dòng)日志記錄,通過(guò)監(jiān)聽(tīng)器去監(jiān)聽(tīng),當(dāng)訪(fǎng)問(wèn)到具體的類(lèi)方法,通過(guò)aop切面去獲取訪(fǎng)問(wèn)的方法,然后將日志記錄下來(lái),就這種方式給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
tio-http-server打包為二進(jìn)制文件的實(shí)現(xiàn)及優(yōu)勢(shì)詳解
這篇文章主要為大家介紹了tio-http-server打包為二進(jìn)制文件實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
CMD運(yùn)行Intellij Idea編譯后的class文件操作
這篇文章主要介紹了CMD運(yùn)行Intellij Idea編譯后的class文件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
Spring?Clou整合?Security?+?Oauth2?+?jwt實(shí)現(xiàn)權(quán)限認(rèn)證的詳細(xì)過(guò)程
本文介紹了如何使用Spring?Cloud、Spring?Security、Oauth2和JWT實(shí)現(xiàn)統(tǒng)一認(rèn)證和權(quán)限管理,并分享了項(xiàng)目結(jié)構(gòu)和主要代碼示例,感興趣的朋友跟隨小編一起看看吧2025-02-02
Java新手學(xué)習(xí)之IO流的簡(jiǎn)單使用
IO主要用于設(shè)備之間的數(shù)據(jù)傳輸,Java將操作數(shù)據(jù)流的功能封裝到了IO包中,這篇文章主要給大家介紹了關(guān)于Java新手學(xué)習(xí)之IO流簡(jiǎn)單使用的相關(guān)資料,需要的朋友可以參考下2021-10-10

