Spring Boot 3 整合 JWT(JSON Web Tokens)用于登录开发涉及多个步骤。JWT 是一种开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。这些信息可以被验证和信任,因为它们是数字签名的。
以下是一个简单的步骤指南,用于在 Spring Boot 3 应用中整合 JWT:
第一种方式
1. 添加依赖
首先,在你的 pom.xml
文件中添加 Spring Boot Web 和 JWT 相关的依赖:
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JWT Library, 例如 jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>你的jjwt版本号</version>
</dependency>
<!-- 如果jdk大于1.8 则需要导入以下依懒 -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb.api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 其他依赖 -->
</dependencies>
注意:你的jdk版本如果为1.8导入第一个就行,大于1.8就要导入两个。
2. 配置 JWT
JWT(JSON Web Token)工具类在实际开发中通常包含以下一些常用方法:
- 生成JWT:用于生成JWT令牌并返回令牌字符串。
- 解析JWT:用于解析JWT令牌,验证签名,并获取其中的声明信息。
- 验证JWT:用于验证JWT的有效性,包括验证签名、过期时间等。
- 刷新JWT:用户还在操作,马上要快过期时,延长其有效期(无感刷新)。
- 其他辅助方法:例如获取JWT中的特定声明信息,验证JWT是否包含某个声明,等等。
2.1、创建 JWT 工具类
创建一个工具类,用于生成和验证 JWT,配置 JWT 的密钥和有效期等:
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 Yun
*/
public class JwtUtils {
private static final String SIGN_KEY = "你的密钥";// 加密密钥
private static final long EXPIRE_TIME = 2 * 60 * 60 * 1000; //到期时间,2小时,单位毫秒
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的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为令牌的唯一标识。
.setIssuedAt(new Date())//设置签发时间
.setSubject("yun")//设置主题,一般为用户类型
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)//设置签名算法,使用HS256算法
.addClaims(claims)//设置负载
.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);
}
}
}
3. 编写测试登录接口
在你的 test目录下创建JwtTest.java文件中,测试代码如下:
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> claim = Map.of("username", "yun", "role", "admin");
// 生成JWT
String jwt = JwtUtils.generateToken(claim, "secret");
System.out.println("JWT: " + jwt);
// 解析JWT
Claims claims = JwtUtils.parseToken(jwt);
// 获取完整的payload
String payload = claims1.toString();
System.out.println("Payload: " + payload);
}
}
第二种方式:交由spring容器管理依赖注入使用
配置文件
在application.properties
或application.yml
文件中配置JWT相关的属性,如密钥、过期时间等。
jwt:
secret: your-secret-key 你的密钥
expiration: 86400000 # 1天,单位:毫秒
注意:此代码用到了lombok的@Data注解,来添加getter 和 setter 方法,请确保有该依赖
<!--lombok-->
<!-- ClassFormatException: Invalid byte tag in constant pool: 19
lombok 版本过高 1.18.x 导致
-->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
jwt工具类如下:
此代码用到了lombok的@Data注解,来添加getter 和 setter 方法,请确保有该依赖
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 yun
*/
@Data
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtUtils {
private String secret; //在application.yml中配置的密钥
private long expiration; //在application.yml设置的过期时间
/**
* 生成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("yun")//设置主题,一般为用户类型
.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);
}
}
}
创建登录接口
在你的 Controller 中,创建处理登录请求的接口:
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 yun
*/
@RestController
@RequestMapping("/api/auth")
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", "yun");
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接口:localhost:8080/api/auth/get-token
复制token
请求解析token接口并路径传参传入复制的token:localhost:8080/api/auth/parse-token/你的token