目录
2.接着添加过期时间,密钥,BASE64解码密钥的属性以及生成token的方法,合并上面生成密钥的方法,下面是完整代码。
3.当然也可以写解析token的方法进行验证,通过对称密钥KEY进行对token进行验证,得到载荷部分:
一、何为令牌
令牌其实就是一个用户身份的标识,其本质上就是一个字符串。
比如我们出行在外,会带着自己的身份证,需要验证身份时,就要身份证了,而身份证不能伪造,可以辨别真假。

服务器具备生成令牌和验证令牌的能力。
JWT令牌
令牌本质就是一个字符串,它的实现方式有很多种,我们采用一个JWT令牌来实现。
介绍
JWT全称:JSON Web Toekn
官网:++https://jwt.io/++
JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),用于客户端和服务器之间传递安全可靠的信息。
其本质是一个token,是一种紧凑的URL安全方法。
JWT组成
JWT由三部分组成,使用(.)分隔,比如:aaaaa.bbbbb.cccc,这三部分为:
- Header(头部):头部包括令牌类型(即JWT)及使用的哈希算法(如HMAC SHA256或RSA)
- Payload(负载):负载部分是存放有效信息的地方,里面是一些自定义的内容。比如:{"userId":"123","userName":"zhangsan"},也可以存在jwt提供的现场字段,比如exp(过期时间戳)等 。注意:此部分不建议存放敏感信息,因为此部分能够被解码还原原始内容
- Signature(签名):此部分用于防止jwt内容被篡改,确保安全性。
防止被篡改,而不是防止被解析。
jwt之所以安全,就是因为最后的签名。jwt当中任何一个字符被篡改,整个令牌都会校验失效。这就好比我们的身份证,之所以能标识一个人的身份,是因为不能被篡改,而不是因为内容加密。
二、JWT用于验证用户登录
具体流程如下
++1.用户登录(生成JWT)++
(1)用户提交凭证
* 场景:用户输入用户名和密码,点击登录。
(2)认证服务器验证凭证
验证流程:
* 检查用户名和密码是否匹配数据库中的记录
* 确认用户状态(是否被禁用)
(3)生成JWT
JWT结构:
* Header:声明算法类型(如"alg": "RS256", "typ": "JWT"}
).
* Payload:包含用户身份和权限信息({"sub": "user123", "roles": ["user"], "exp": 1720000000}
)。
* Signature:使用私钥对头部和载荷签名 (如 RSA-SHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), privateKey)
)。
++2.客户端存储并携带JWT++
客户端把令牌存储起来,可以存储在Cookie中,也可以存储在其他的存储空间。
++3.服务器验证JWT++
(1)解析JWT结构
(2)验证签名
非对称加密流程:从认证服务器获取公钥,使用公钥重新计算签名,比对JWT中的签名是否一致。同时验证令牌是否有效,有效就说明执行了登录操作,否则就是未登录。
总结:
1.用户登录请求,经过负载均衡,把请求转给了第一台服务器,第一台服务器进行账号密码验证,验证成功后,生成一个令牌,并返回给客户端。
2.客户端收到令牌后,把令牌存储起来,可以存储在Cookie中,也可以存储在其他的存储空间。
3.用户登录成功后,携带令牌继续执行查询操作,比如查询博客列表,此时请求转发到了第二台机器 ,第二台机器会先进行权限验证操作。服务器验证令牌是否有效,就说明执行了登录操作,如果令牌是无效的,就说明用户之前未执行登录操作。
三、JWT令牌生成和校验
在使用之前先引入相关的依赖:
放在<dependencies> </dependencies>标签下:
XML
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is
preferred -->
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
简单用法
主要思想是利用生成的对称密钥对token进行签名(加密)和验证(解密)。
++下面代码主要利用测试类进行讲解:++
1.创建生成密钥的方法
java
@Test
public void genKey(){
//随机生成一个key,HS256算法生成 。H256是一种堆成密钥算法
SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
//利用BASE64对密钥进行编码
String key = Encoders.BASE64.encode(secretKey.getEncoded());
System.out.println(key);
}
运行后生成结果如下:
java
B2S6Xk0/9aDxArJCaVWEAa2moixi3RVx+O8oraRQ3cQ=
2.接着添加过期时间,密钥,BASE64解码密钥的属性以及生成token的方法,合并上面生成密钥的方法,下面是完整代码。
java
@SpringBootTest
public class JWTUtilTest {
//过期毫秒时长10年
public static final long Expiration =10 * 365 * 24 * 60 * 60 * 1000L;;
//密钥,就是利用下面genKey()方法生成的密钥
private static final String secretSrting =
"B2S6Xk0/9aDxArJCaVWEAa2moixi3RVx+O8oraRQ3cQ=";
//生成安全密钥,BASE64解码
private static final SecretKey KEY =
Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretSrting));
//生成token
@Test
public void genToken(){
//生成载荷部分
Map<String,Object> claim = new HashMap<>();
claim.put("id",1);
claim.put("username","zhangsan");
//自定义信息
String jwt = Jwts.builder()
.setClaims(claim)//自定义内容(负载)
.setExpiration(new Date(System.currentTimeMillis()+Expiration))//设置过期时间
.signWith(KEY) //密钥签名
.compact();
System.out.println(jwt);
}
//生成密钥
@Test
public void genKey(){
//随机生成一个key,HS256算法生成
SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
String key = Encoders.BASE64.encode(secretKey.getEncoded());
System.out.println(key);
}
}
运行genToken()方法,得到token字符串。
java
eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJ6aGFuZ3NhbiIsImV4cCI6MjA2MTAwMTY0OX0.
7eFIjaWuKEZTFnBlrVgdVtplVowslGnd_VHenj3qQpU

3.当然也可以写解析token的方法进行验证,通过++对称密钥KEY进行对token进行验证++,得到载荷部分:
java
//校验token信息
@Test
public void parseToken(){
String token ="eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJ6aGFuZ3NhbiIsImV4cCI6MjA2MTAwMTY0OX0.7eFIjaWuKEZTFnBlrVgdVtplVowslGnd_VHenj3qQpU";
//利用对称密钥再进行验证token
JwtParser bulid = Jwts.parserBuilder().setSigningKey(KEY).build();
Claims body = bulid.parseClaimsJws(token).getBody();
System.out.println(body);
}
运行结果如下:

进阶用法
处于安全考虑,我们可以通过RSA算法生成非对称密钥,利用私钥签名,利用公钥进行验证,同时通过还需要这对对密钥进行管理,将其管理在密钥库中。
++下面是实现步骤:++
1.创建密钥库文件(JKS)
我们需要把生成这对对 公钥-私钥 ,并将其保存在密钥库中。可以使用keytool命令创建JKS文件(在idea中的终端运行)。
命令如下:
java
keytool -genkeypair -alias myalias -keyalg RSA -keysize 2048 -keystore mykeystore.jks -storepass keystorepass -validity 365
命令解析:
keytool -genkeypair \ -alias myalias \ # 密钥条目别名(自定义标识) -keyalg RSA \ # 密钥算法(RSA 非对称加密) -keysize 2048 \ # 密钥长度(2048 位,安全推荐值) -keystore mykeystore.jks \# 密钥库文件名(保存路径) -storepass keystorepass \ # 密钥库密码(保护整个文件) -validity 365 # 证书有效期(365 天)
此命令用于生成一个java密钥库(JKS文件),并在其中创建一个RSA密钥(非对称)对。
运行后keytool会提示输入相关信息(学习阶段随便填即可):
java
您的名字与姓氏是什么?
[Unknown]: localhost # 建议填域名(如服务器域名或本地测试填 localhost)
您的组织单位名称是什么?
[Unknown]: MyOrg # 组织单位(可选)
您的组织名称是什么?
[Unknown]: MyCompany # 组织名称(可选)
您所在的城市或区域名称是什么?
[Unknown]: Beijing # 城市(可选)
您所在的省/市/自治区名称是什么?
[Unknown]: Beijing # 省份(可选)
该单位的双字母国家/地区代码是什么?
[Unknown]: CN # 国家代码(如 CN 表示中国)
CN=localhost, OU=MyOrg, O=MyCompany, L=Beijing, ST=Beijing, C=CN是否正确?
[否]: 是 # 确认信息
输入完后,会提示输入口令,++注意这个口令是和后面获取私钥的时候挂钩的++,我们可以直接按回车和密钥库密码一样,同时也可以自定义。
输入完后,项目里面会生成jks文件,我们可以剪贴到resource目录下,后面需要该文件路径。

2.读取JKS密钥库并进行签名,生成token
下面是详细代码:
java
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.util.Date;
import java.util.Map;
public class JWTUtils {
// EYSTORE_PASSWORD(密钥库密码):用于保护整个 JKS 密钥库文件。在加载密钥库时需要使用此密码。
//配置密钥库的路径、别名。访问密码
private static final String KETSTORE_PATH = "src/main/resources/mykeystore.jks";
//密钥库密码
private static final String KEYSTORE_PASSWORD = "keystorepass";
//密钥别名
private static final String KEY_ALIAS = "myalias";
//访问私钥的密码(刚刚自己输入的口令)
private static final String KEY_PASSWORD = "123456";
//从jks文件中加载私钥
private static Key getPrivateKey() throws Exception {
KeyStore keyStore = KeyStore.getInstance("JKS");
try (FileInputStream keyStoreStream = new FileInputStream(KETSTORE_PATH)){
keyStore.load(keyStoreStream, KEYSTORE_PASSWORD.toCharArray());
}
return keyStore.getKey(KEY_ALIAS, KEY_PASSWORD.toCharArray());
}
//生成TOKEN
public static String generateToken(Map<String,Object> claim)throws Exception{
Key privateKey = getPrivateKey();
return Jwts.builder()
.setClaims(claim)//自定义内容(负载)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis()+60*60*1000)) //过期时间1小时
.signWith(privateKey, SignatureAlgorithm.RS256) //使用私钥签名,相当于用私钥加密
.compact();
}
}
3.验证Token
java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;
public class JwtValidator {
//获取公钥,公钥无需密码去访问直接获取即可
private static PublicKey getpublicKey()throws Exception{
KeyStore keyStore = KeyStore.getInstance("JKS");
try (FileInputStream keyStoreStream = new FileInputStream("src/main/resources/mykeystore.jks")) {
keyStore.load(keyStoreStream,"keystorepass".toCharArray());
}
return keyStore.getCertificate("myalias").getPublicKey();
}
//验证JWT并解析
public static Claims validateToken(String token)throws Exception{
PublicKey publicKey = getpublicKey();
return Jwts.parserBuilder()
.setSigningKey(publicKey) //使用公钥验证
.build()
.parseClaimsJws(token)//解析jwt
.getBody();
}
//运行main方法执行程序
public static void main(String[] args) throws Exception {
//写入相关参数
Map<String,Object> claim = new HashMap<>();
claim.put("id",1);
claim.put("username","zhangsan");
String token = JWTUtils.generateToken(claim);
// System.out.println(token);
Claims claims = validateToken(token);
System.out.println(claims);
}
}
运行结果:

以上是JWT令牌的讲解,喜欢的支持一下,感谢观看!!!