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

posted @ 2024-07-08 11:16  xd99  阅读(354)  评论(0)    收藏  举报