一文讲清楚JWT的原理和使用(附详细案例代码)
01-JWT是什么
JWT(JSON Web Token)是一种开放的行业标准(RFC 7519),用于安全地双方之间传输信息,常用于各方之间传输信息,特别是在身份认证领域使用非常广泛;
02-JWT的数据结构
JWT的数据结构如下所示:

- 它是一个很长的字符串,中间用点(.)分隔成三个部分;
- 注意,JWT内部是没有换行的,这里只是为了便于展示,将它写成了几行;
JWT的三个部分依次是:
- Header(头部)
- Payload(负载) 这里面可以携带业务数据(比如一些参数)
- Signature(签名)
写成一行,就是下面的样子:Header.Payload.Signature

2.1 Header
Header部分原文是一个JSON对象,描述JWT的元数据,通常如下:
{
"alg": "HS256",
"typ": "JWT"
}
- alg属性:表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);
- typ属性:表示这个令牌(token)的类型(type),JWT令牌统一写为JWT;
最后,将上面的JSON对象使用 Base64URL算法 转成字符串,就得到Header部分;
2.2 Payload
Payload 部分原文也是一个JSON对象,用来 存放实际需要传递的数据,JWT定义了7个官方字段供选用:
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
我们可以不使用官方的字段,我们可以使用任何字段来传递数据,只要是个JSON就行,比如:
{
"number": "1234567890",
"name": "cat",
"phone": "13700000000"
}
这个JSON 对象也要使用 Base64URL算法 转成字符串;
注意,Base64URL 算法不是加密算法,它是 编码算法,是可以解码出原文的,也就是JWT负载中的数据任何人都可以解码得到原文(不安全),所以不要把私密信息(密码,验证码等)放在这个部分;(虽然可以解码出来,但是我们把密码比如加密之后再放在负载里面,也是没有问题,是安全的)
2.3 Signature
Signature 部分是对前两部分的签名,防止数据篡改;
首先,需要指定一个密钥(secret),这个密钥只有服务器才知道,不能泄露给用户,然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式(两个参数)产生签名:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户;
base64UrlEncode(header) . base64UrlEncode(payload) . HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload), secret)
样式示例:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJudW1iZXIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImNhdCIsInBob25lIjoiMTM3MDAwMDAwMDAifQ.cGLcaxSyl9dgiL_hK5wv1Pbgj8PGHFVXEWReDvW0lN4
03-SpringBoot项目中JWT使用示例
3.1 添加JWT依赖
添加 jwt 依赖的两种方式
<!-- 使用java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
<!-- 使用hutool工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-jwt</artifactId>
<version>5.8.41</version>
</dependency>
3.2 使用java-jwt封装JWT工具类
封装JWT工具类使用
/**
* JWT工具类:主要就解决三个问题
*/
public class JavaJWTUtil {
/**
* 密钥
*/
public static final String secret = "day281hd9nso;scna/cnOHDUchia7U91=";
/**
* 生成JWT字符串
*/
public static String createToken(String userJson) {
//组装头数据
Map<String, Object> header = new HashMap<>();
header.put("alg", "HS256");
header.put("typ", "JWT");
return JWT.create()
// 头部
.withHeader(header)
// 负载:可以放多个数据
.withClaim("user", userJson)
.withClaim("phone", "13133682689")
.withClaim("birthday", new Date(1990, Calendar.MARCH, 3))
// 签名
.sign(Algorithm.HMAC256(secret));
}
/**
* 验证JWT有没有被篡改
*
* @param token 要验证的jwt的字符串
*/
public static Boolean verifyToken(String token) {
try {
// 使用密钥创建一个jwt解析对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secret)).build();
// 使用验证器对象验证JWT,如果验证没有抛出异常,则验证通过;反之就是没通过
jwtVerifier.verify(token);
// 如果没有抛出异常,返回 true 表示验证通过
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 解析出JWT里面的负载数据
*
* @param token 要解析的jwt的字符串
* @return
*/
public static String parseToken(String token) {
try {
// 使用密钥创建一个jwt验证器对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secret)).build();
// 验证JWT,得到一个解码后的JWT对象
DecodedJWT decodedJWT = jwtVerifier.verify(token);
// 通过解码后的验证器对象获取负载数据
Claim user = decodedJWT.getClaim("user");
System.out.println(user.asString());
Claim phone = decodedJWT.getClaim("phone");
System.out.println(phone.asString());
Claim birthday = decodedJWT.getClaim("birthday");
System.out.println(birthday.asDate());
return user.asString();
} catch (TokenExpiredException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
编写测试代码:
public class testJavaJwt {
public static void main(String[] args) {
TUser tUser = TUser.builder().id(10089).loginAct("John").email("3072107986@qq.com").build();
String jsonStr = JSONUtil.toJsonStr(tUser);
// 生成JWT字符串
String token = createToken(jsonStr);
System.out.println(token);
// 验证JWT
Boolean verify = verifyToken(token + 123);
System.out.println("验证结果:" + verify);
// 解析JWT
parseToken(token);
}
}
运行效果:验证时传入的token和之前生成时使用的token不一致,解析失败,抛出异常

3.3 使用hutool-jwt操作jwt
使用 hutool 包就不用自己写工具类了,它基本都封装好了
3.3.1 生成JWT
JWTUtil.createToken() 方法生成 JWT
public class HutoolJWTTest {
// 密钥不能让别人知道,这个密钥放在服务器上
public static final String secret = "0S/12d4845Whd2h3OPYs";
public static void main(String[] args) {
// 生成JWT
Map<String, Object> header = new HashMap<>(); // 头部
header.put("alg", "HS256");
header.put("typ", "JWT");
Map<String, Object> payLoad = new HashMap<>(); // 负载
payLoad.put("id", 12352);
payLoad.put("phone", "13720202020");
payLoad.put("birthDay", new Date());
// 四个重载方法
String jwt = JWTUtil.createToken(payLoad, secret.getBytes(StandardCharsets.UTF_8));
System.out.println(jwt);
String jwt2 = JWTUtil.createToken(payLoad, JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8)));
System.out.println(jwt2);
String jwt3 = JWTUtil.createToken(header, payLoad, secret.getBytes(StandardCharsets.UTF_8));
System.out.println(jwt3);
String jwt4 = JWTUtil.createToken(header, payLoad, JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8)));
System.out.println(jwt4);
}
}
可以看到,运行效果都是一样的
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJiaXJ0aERheSI6MTc2NTI3MDQ1NiwicGhvbmUiOiIxMzcyMDIwMjAyMCIsImlkIjoxMjM1Mn0.4VLZXBdQ3CJOKuppMCZ1XiStatrcQv1ueMKFTxgzCAI
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJiaXJ0aERheSI6MTc2NTI3MDQ1NiwicGhvbmUiOiIxMzcyMDIwMjAyMCIsImlkIjoxMjM1Mn0.4VLZXBdQ3CJOKuppMCZ1XiStatrcQv1ueMKFTxgzCAI
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJiaXJ0aERheSI6MTc2NTI3MDQ1NiwicGhvbmUiOiIxMzcyMDIwMjAyMCIsImlkIjoxMjM1Mn0.4VLZXBdQ3CJOKuppMCZ1XiStatrcQv1ueMKFTxgzCAI
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJiaXJ0aERheSI6MTc2NTI3MDQ1NiwicGhvbmUiOiIxMzcyMDIwMjAyMCIsImlkIjoxMjM1Mn0.4VLZXBdQ3CJOKuppMCZ1XiStatrcQv1ueMKFTxgzCAI
3.3.2 验证JWT
JWTUtil.verify() 方法验证 JWT
public class HutoolJWTTest {
// 密钥不能让别人知道,这个密钥放在服务器上
public static final String secret = "0S/12d4845Whd2h3OPYs";
public static void main(String[] args) {
// 生成JWT
Map<String, Object> header = new HashMap<>(); // 头部
header.put("alg", "HS256");
header.put("typ", "JWT");
Map<String, Object> payLoad = new HashMap<>(); // 负载
payLoad.put("id", 12352);
payLoad.put("phone", "13720202020");
payLoad.put("birthDay", new Date());
String jwt4 = JWTUtil.createToken(header, payLoad, JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8)));
// 2、验证jwt 两个负载方法
boolean verify = JWTUtil.verify(jwt4, secret.getBytes(StandardCharsets.UTF_8));
boolean verify2 = JWTUtil.verify(jwt4, JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8)));
System.out.println(verify);
System.out.println(verify2);
}
}
运行效果:
true
true
3.3.3 解析JWT
* 使用 JWTPayload 中的 getClaim() 方法返回 Object 对象,除了String,其它类型进行强制类型转换会报错
public class HutoolJWTTest {
// 密钥不能让别人知道,这个密钥放在服务器上
public static final String secret = "0S/12d4845Whd2h3OPYs";
public static void main(String[] args) {
// 生成JWT
Map<String, Object> header = new HashMap<>(); // 头部
header.put("alg", "HS256");
header.put("typ", "JWT");
Map<String, Object> payLoad = new HashMap<>(); // 负载
payLoad.put("id", 12352);
payLoad.put("phone", "13720202020");
payLoad.put("birthDay", new Date());
String jwt4 = JWTUtil.createToken(header, payLoad, JWTSignerUtil.hs256(secret.getBytes(StandardCharsets.UTF_8)))
//3、解析jwt负载中的数据
JWT parseJWT = JWTUtil.parseToken(jwt4);
// 拿数据一般就是拿 payload 中的
JWTPayload payload = parseJWT.getPayload();
// getClaim() 方法返回 Object 对象
Object id = payload.getClaim("id");
String phone = (String) payload.getClaim("phone");
Object birthDay = payload.getClaim("birthDay");
System.out.println(id + " -- " + phone + " -- " + birthDay);
}
}
// 结果:12352 -- 13720202020 -- 1765271748
* 使用 getPayloads() 方法获取 JSONObject 类对象,调用它的 get() 方法并指定属性类型;payload中就是按JSON格式存储的
public class HutoolJWTTest {
public static void main(String[] args) {
// 生成 和 验证 代码同上 ……
//3、解析jwt负载中的数据
JWT parseJWT = JWTUtil.parseToken(jwt4);
// 拿数据一般就是拿 payload 中的
JSONObject payloads = parseJWT.getPayloads();
Integer id2 = payloads.get("id", Integer.class);
String phone2 = payloads.get("phone", String.class);
Date birthDay2 = payloads.get("birthDay", Date.class);
System.out.println(id2 + " -- " + phone2 + " -- " + birthDay2);
}
}
// 结果:12352 -- 13720202020 -- 2025-12-09 17:15:48
* 使用 getPayload(String name) 方法获取到 Object 对象,也不能进行向下转型
public class HutoolJWTTest {
public static void main(String[] args) {
// 生成 和 验证 代码同上 ……
//3、解析jwt负载中的数据
JWT parseJWT = JWTUtil.parseToken(jwt4);
// 拿数据一般就是拿 payload 中的
Object id3 = parseJWT.getPayload("id");
Object phone3 = parseJWT.getPayload("phone");
Object birthDay3 = parseJWT.getPayload("birthDay");
System.out.println(id3 + " -- " + phone3 + " -- " + birthDay3);
}
}
// 结果:12352 -- 13720202020 -- 1765271748
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)