JWT令牌 和 拦截器的编写与注册 (配置拦截器后knife4j不能正常访问的解决办法)
首先在pom.xml引入依赖
<!--jwt坐标-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
JwtUtil
package com.zxd.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
private static final String KEY = "itzxd";
/**
* 生成JWT令牌。
*
* @param claims 令牌中包含的声明,这些声明是JWT的一部分,可以包含用户信息或其他业务数据。
* @return 生成的JWT令牌字符串。
*
* 该方法通过使用HMAC256算法签名来创建一个带有所指定声明的JWT令牌。
* 令牌的有效期设置为12小时,从当前时间开始计算。
*/
//接收业务数据,生成token并返回
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
.sign(Algorithm.HMAC256(KEY));
}
/**
* 解析JWT令牌并返回其中的声明。
*
* 该方法用于验证JWT令牌的有效性,并提取令牌中包含的特定声明。
* 使用HMAC256算法对令牌进行验证,确保令牌未被篡改。
* 特别是,它提取了名为"claims"的声明,并将其作为Map返回,以便进一步处理。
*
* @param token 待解析的JWT令牌。
* @return 包含JWT令牌中"claims"声明的Map对象,如果令牌验证失败,则可能为空。
*/
//接收token,验证token,并返回业务数据
public static Map<String, Object> parseToken(String token) {
return JWT.require(Algorithm.HMAC256(KEY))
.build()
.verify(token)
.getClaim("claims")
.asMap();
}
}
引入测试类
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
测试类代码
JwtTest
package com.zxd.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtil {
/**
* JWT令牌的密钥。
*
* 该常量用于生成和验证JWT令牌。
* 它是一个字符串,用于对令牌进行签名和验证。
*/
private static final String KEY = "itzxd";
/**
* 生成JWT令牌。
*
* @param claims 令牌中包含的声明,这些声明是JWT的一部分,可以包含用户信息或其他业务数据。
* @return 生成的JWT令牌字符串。
*
* 该方法通过使用HMAC256算法签名来创建一个带有所指定声明的JWT令牌。
* 令牌的有效期设置为12小时,从当前时间开始计算。
*/
//接收业务数据,生成token并返回
public static String genToken(Map<String, Object> claims) {
return JWT.create()
.withClaim("claims", claims)
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12))
.sign(Algorithm.HMAC256(KEY));
}
/**
* 解析JWT令牌并返回其中的声明。
*
* 该方法用于验证JWT令牌的有效性,并提取令牌中包含的特定声明。
* 使用HMAC256算法对令牌进行验证,确保令牌未被篡改。
* 特别是,它提取了名为"claims"的声明,并将其作为Map返回,以便进一步处理。
*
* @param token 待解析的JWT令牌。
* @return 包含JWT令牌中"claims"声明的Map对象,如果令牌验证失败,则可能为空。
*/
//接收token,验证token,并返回业务数据
public static Map<String, Object> parseToken(String token) {
return JWT.require(Algorithm.HMAC256(KEY))
.build()
.verify(token)
.getClaim("claims")
.asMap();
}
}
生成JWT令牌测试类代码
@Test //生成jwt令牌
public void testGen(){
// 初始化一个Map用于存储JWT的声明(claims)
Map<String,Object> claims = new HashMap<>();
// 模拟入参
claims.put("id",1);
claims.put("username","zxd");
// 创建JWT,设置用户声明、过期时间和签名算法
String token = JWT.create()
.withClaim("user",claims)// 添加载荷
.withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7))//添加过期时间
.sign(Algorithm.HMAC256("itzxd"));//指定算法,配置秘钥,此秘钥不可泄露
System.out.println(token);
}
解析和验证JWT令牌测试类代码
@Test //token解析
public void testParse(){
// 模拟用户传递过来的token
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6Inp4ZCJ9LCJleHAiOjE3MjEwMTI2OTZ9.xe7TEy1H7UmBxt0I-QjW1wOD43a7kFCyymnWvFyHfpc";
// 创建JWT验证器,使用HMAC256算法,密钥为"itzxd"
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("itzxd")).build();
// 使用验证器验证JWT令牌的有效性,并返回解析后的JWT对象
DecodedJWT decodedJWT = jwtVerifier.verify(token);
// 提取JWT中的声明(claims)
Map<String, Claim> claim = decodedJWT.getClaims();
// 输出声明中名为"user"的值
System.out.println(claim.get("user"));
// 如果篡改了头部和载荷部分的数据,验证失败
// 如果篡改了秘钥部分,验证失败
// token过期,验证失败
}
拦截器的编写
LoginInterceptor
package com.zxd.interceptors;
import com.zxd.utils.JwtUtil;
import com.zxd.utils.ThreadLocalUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Map;
/**
* @Auther: Zxd
* @Date: 2024/07/08 14:13
* @Description:
*/
@Component // 将拦截器注册到IOC容器中
public class LoginInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 令牌验证
String token = request.getHeader("Authorization");
// 验证token
try {
Map<String, Object> claims = JwtUtil.parseToken(token);
// 把业务数据存储到ThreadLocal中
ThreadLocalUtil.set(claims);
// 放行
return true;
} catch (Exception e) {
// 响应状态码为401
response.setStatus(401);
// 不放行
return false;
}
}
//afterCompletion方法在执行完Handler之后执行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 清空ThreadLocal中存储的数据
ThreadLocalUtil.remove();
}
}
@Component // 将拦截器注册到IOC容器中
public class LoginInterceptor implements HandlerInterceptor {
//目标资源方法执行前执行。 返回true:放行 返回false:不放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 令牌验证
String token = request.getHeader("Authorization");
// 验证token
try {
Map<String, Object> claims = JwtUtil.parseToken(token);
// 放行
return true;
} catch (Exception e) {
// 响应状态码为401
response.setStatus(401);
// 不放行
return false;
}
}
}
注册拦截器并配置不拦截路径
WebConfig拦截器
package com.zxd.config;
import com.zxd.interceptors.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Auther: Zxd
* @Date: 2024/07/08 14:19
* @Description:
*/
@Configuration // 声明是一个配置类
public class WebConfig implements WebMvcConfigurer {
@Override // 声明重写父类的方法
public void addInterceptors(InterceptorRegistry registry) {
// 登录接口和注册接口不拦截
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**") // 注册定义好的拦截器
.excludePathPatterns( // 添加不拦截路径
"/user/login", //登录页面
"/user/register", //注册页面
"/doc.html/**", // knife4j页面
"/swagger-resources/**",
"/webjars/**",
"/v3/**"
);
}
}
@Configuration // 声明是一个配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired // 注入拦截器
private LoginInterceptor loginInterceptor;
@Override // 声明重写父类的方法
public void addInterceptors(InterceptorRegistry registry) {
// 登录接口和注册接口不拦截
registry.addInterceptor(loginInterceptor) // 注册定义好的拦截器
.excludePathPatterns( // 添加不拦截路径
"/user/login", //登录页面
"/user/register" //注册页面
);
}
}
SpringBoot3登录拦截器导致不能正常访问knife4j
在拦截器下加入
"/doc.html/**", // knife4j页面
"/swagger-resources/**",
"/webjars/**",
"/v3/**"
https://blog.csdn.net/EpiphyllumLove/article/details/134231795

浙公网安备 33010602011771号