⛰️个人主页: 蒾酒
🔥系列专栏:《spring boot实战》
🌊山高路远,行路漫漫,终有归途。
目录
前置条件
jwt简介
导依赖
编写jwt工具类
1.配置项直接嵌入代码,通过类名.静态方法使用
前置条件
已经初始化好一个spring boot项目且版本为3X,项目可正常启动。
作者版本为3.2.2
初始化教程:
新版idea创建spring boot项目-CSDN博客文章浏览阅读2.5k次,点赞60次,收藏66次。本教程对新手小白友好。若根据教程创建出现问题导致失败可下载我提供的源码,在文章最后。本教程较新本文使用的工具以及搭建的springboot版本都是很新版本:idea版本如下spring boot 版本如下:本教程使用的是汉化后的idea。https://blog.csdn.net/qq_62262918/article/details/135785412?spm=1001.2014.3001.5501
jwt简介
- JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用间传输和存储信息的一种安全方式。
- 它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
- JWT可以被用作身份验证和授权,通过在服务器和客户端之间传递令牌来验证用户的身份并允许访问受保护的资源。
- 由于JWT是基于数字签名的,所以可以确保数据的完整性和安全性。它的设计简单、易于实现,并且可以跨不同的平台和语言使用。
导依赖
pom.xml:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- 如果jdk大于1.8,则还需导入下面依赖-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
注意:你的jdk版本如果为1.8导入第一个就行,大于1.8就要导入两个。
编写jwt工具类
JWT(JSON Web Token)工具类在实际开发中通常包含以下一些常用方法:
- 生成JWT:用于生成JWT令牌并返回令牌字符串。
- 解析JWT:用于解析JWT令牌,验证签名,并获取其中的声明信息。
- 验证JWT:用于验证JWT的有效性,包括验证签名、过期时间等。
- 刷新JWT:用户还在操作,马上要快过期时,延长其有效期(无感刷新)。
- 其他辅助方法:例如获取JWT中的特定声明信息,验证JWT是否包含某个声明,等等。
其中生成和解析token是必须的,其他方法根据项目需求设计来决定写不写。
1.配置项直接嵌入代码,通过类名.静态方法使用
jwt工具类如下:
上面五种常用方法已经写好,cv过来直接能用。按需修改也可以。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;
/**
* @author mijiupro
*/
public class JwtUtils {
private static final String SIGN_KEY = "mijiu";// 加密密钥
private static final long EXPIRE_TIME = 12 * 60 * 60 * 1000; //到期时间,12小时,单位毫秒
private static final byte[] SECRET_KEY = SIGN_KEY.getBytes(StandardCharsets.UTF_8);
/**
* 生成token令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @param subject 主题(用户类型)
* @return token
*/
public static String generateToken(Map<String,Object> claims, String subject) {
return Jwts.builder()
.setId(Claims.ID)//设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为令牌的唯一标识。
.setSubject("mijiu")//设置主题,一般为用户类型
.setIssuedAt(new Date())//设置签发时间
.addClaims(claims)//设置负载
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)//设置签名算法
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))//设置令牌过期时间
.compact();//生成令牌
}
/**
* 解析token令牌
* @param token token令牌
* @return 负载
*/
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
/**
* 验证token令牌
* @param token 令牌
* @return 是否有效
*/
public static boolean validateToken(String token) {
try {
Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return true;
} catch (Exception e) {
return false;
}
}
/**
* 刷新Token
* @param token 旧的Token令牌
* @return 新的Token令牌
*/
public static String refreshToken(String token) {
try {
// 解析旧的Token,获取负载信息
Claims claims = parseToken(token);
// 生成新的Token,设置过期时间和签名算法等参数
return generateToken(claims, claims.getSubject());
} catch (Exception e) {
throw new RuntimeException("无法刷新令牌!", e);
}
}
/**
* 从令牌中获取主题信息
* @param token 令牌
* @return 主题信息(用户类型)
*/
public static String getSubjectFromToken(String token) {
try {
Claims claims = parseToken(token); // 解析令牌,获取负载信息
return claims.getSubject(); // 返回主题信息
} catch (Exception e) {
throw new RuntimeException("无法从令牌中获取主题。", e);
}
}
}
编写测试
测试代码如下:
import com.mijiu.commom.util.JwtUtils;
import io.jsonwebtoken.Claims;
import org.junit.jupiter.api.Test;
import java.util.Map;
public class JwtTest {
@Test
public void testJwt() {
// 设置JWT的payload
Map<String, Object> claims = Map.of("username", "mijiu", "role", "admin");
// 生成JWT
String jwt = JwtUtils.generateToken(claims, "secret");
System.out.println("JWT: " + jwt);
// 解析JWT
Claims claims1 = JwtUtils.parseToken(jwt);
// 获取完整的payload
String payload = claims1.toString();
System.out.println("Payload: " + payload);
}
}
作者目录结构
运行测试代码
测试通过
2.配置项写到application.yml,交由spring容器管理依赖注入使用
jwt工具类如下:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
/**
* @author mijiupro
*/
@Data
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtUtils {
private String secret;//密钥
private long expiration;//过期时间
/**
* 生成token令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @param subject 主题(用户类型)
* @return token
*/
public String generateToken(Map<String,Object> claims, String subject) {
return Jwts.builder()
.setId(Claims.ID)//设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为令牌的唯一标识。
.setSubject("mijiu")//设置主题,一般为用户类型
.setIssuedAt(new Date())//设置签发时间
.addClaims(claims)//设置负载
.signWith(SignatureAlgorithm.HS256, secret)//设置签名算法
.setExpiration(new Date(System.currentTimeMillis() + expiration))//设置令牌过期时间
.compact();//生成令牌
}
/**
* 解析token令牌
* @param token token令牌
* @return 负载
*/
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 验证token令牌
* @param token 令牌
* @return 是否有效
*/
public boolean validateToken(String token) {
try {
Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
return true;
} catch (Exception e) {
return false;
}
}
/**
* 刷新Token
* @param token 旧的Token令牌
* @return 新的Token令牌
*/
public String refreshToken(String token) {
try {
// 解析旧的Token,获取负载信息
Claims claims = parseToken(token);
// 生成新的Token,设置过期时间和签名算法等参数
return generateToken(claims, claims.getSubject());
} catch (Exception e) {
throw new RuntimeException("无法刷新令牌!", e);
}
}
/**
* 从令牌中获取主题信息
* @param token 令牌
* @return 主题信息(用户类型)
*/
public String getSubjectFromToken(String token) {
try {
Claims claims = parseToken(token); // 解析令牌,获取负载信息
return claims.getSubject(); // 返回主题信息
} catch (Exception e) {
throw new RuntimeException("无法从令牌中获取主题。", e);
}
}
}
注意:此代码用到了lombok的@Data注解,来添加getter 和 setter 方法,请确保有该依赖
依赖坐标:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
配置文件添加jwt的配置项
application.yml:
jwt:
secret: 123456 #密钥
expiration: 43200000 #过期时间 12h
编写测试类
import com.mijiu.commom.util.JwtUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author mijiupro
*/
@RestController
@RequestMapping("/test")
public class TestController {
private final JwtUtils jwtUtils;
public TestController(JwtUtils jwtUtils) {
this.jwtUtils = jwtUtils;
}
@GetMapping("/get-token")
public String getToken() {
Map<String, Object> claims = new HashMap<>();
claims.put("username", "mijiu");
claims.put("role", "admin");
return jwtUtils.generateToken(claims,"user");
}
@GetMapping("/parse-token/{token}")
public String parseToken(@PathVariable String token) {
return jwtUtils.parseToken(token).toString();
}
}
目录结构
启动项目
请求jwt测试接口
生成token接口:
复制token
请求解析token接口并路径传参传入复制的token
测试成功。