JWT的使用,以及在springboot项目中配置token和拦截验证

前置工作

controller类

由于是简单介绍,所以不会使用service和mapper。

@RestController
public class UserController {

    @GetMapping("/health")
    public String healthCheck() {
        return "OK";
    }
    @GetMapping("/login")
    public String login() {
        Map<String, Object> map = new HashMap<>();
        map.put("id",1);
        map.put("name","username");
        String token = JwtUtil.creatToken(map, JwtProperties.EXPIRET_TIME, JwtProperties.SECRET_KEY);
        return "token = " + token;
    }
}

 jwt配置类

把jwt令牌的签名秘钥和过期时间等解耦出来,下面还会有更好的写法。

public class JwtProperties {

    /**
     * jwt令牌相关配置
     */
    public static final String SECRET_KEY = "secretKey";//签名秘钥
    public static final int EXPIRET_TIME = 7;//过期时间,单位:天
}

一、Jwt的使用

Jwt常用来生成token和解析token去实现登录检验功能。

jwt生成的token是一个字符串,由三部分组成,分别是Header、Payload、Signature

本文不会重点介绍jwt的各个部分,对jwt组成感兴趣请参考博客JWT详解-CSDN博客

1.在pom文件中引入依赖

        <!--jwt令牌依赖-->
        <!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.4.0</version>
        </dependency>

2.编写一个 jwt 的 util 类,实现生成token

1)第一种写法

这种写法不会使用jwt配置类。

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Map;

@Component
@Slf4j
public class JwtUtil {

    private static final String SECRET_KEY = "secretKey";//签名秘钥
    private static final int EXPIRET_TIME = 7;//过期时间,单位为天
    /**
     * 生成token : header-payload-singature
     */
    public static String creatToken(Map<String, Object> map) {

        Calendar instance = Calendar.getInstance();
        // 默认7天过期
        instance.add(Calendar.DATE, EXPIRET_TIME);
        String token = JWT.create()
                .withPayload(map)//载荷内容 payload
                .withExpiresAt(instance.getTime()) // 指定令牌的过期时间
                .sign(Algorithm.HMAC256(SECRET_KEY));//签名
        return token;
    }

    /**
     * 获取token信息方法
     */
    public static Map parseToken(String token) {
        // 通过签名生成验证对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
        DecodedJWT verify = jwtVerifier.verify(token);
        log.info("payload =  {} ", verify.getClaims());
        return verify.getClaims();

    }

}

这里生成token的秘钥签名和过期时间也可以是由自己传入的,如下:

2)第二种写法

使用配置类的写法。

本人用的这种写法。

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Map;

@Component
@Slf4j
public class JwtUtil {

    /**
     * 生成token : header-payload-singature
     */
    public static String creatToken(Map<String, Object> map, int expiretTime, String secretKey) {

        Calendar instance = Calendar.getInstance();
        // 默认7天过期
        instance.add(Calendar.DATE, expiretTime);
        String token = JWT.create()
                .withPayload(map)//载荷内容 payload
                .withExpiresAt(instance.getTime()) // 指定令牌的过期时间
                .sign(Algorithm.HMAC256(secretKey));//签名
        return token;
    }

    /**
     * 获取token信息方法
     */
    public static Map parseToken(String token, String secretKey) {
        // 通过签名生成验证对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secretKey)).build();
        DecodedJWT verify = jwtVerifier.verify(token);
        log.info("payload =  {} ", verify.getClaims());
        return verify.getClaims();

    }

}

如果要使用 jwt 就调用 util 类的静态方法就行。

3.获得token

启动springboot 项目,访问/login 即可获得token返回值。

或者编写test类去获得token。

二、token的登录拦截校验

1.拦截器的功能实现

编写LoginInterceptor 类,去实现HandlerInterceptor 接口,重写preHandle 方法


@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 校验jwt(token)
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader("token");

        if (token == null) {
            throw new Exception("未登录");
        }

        String secretKey = JwtProperties.SECRET_KEY;
        int expiretTime = JwtProperties.EXPIRET_TIME;

        //2、校验令牌
        try {
            log.info("jwt校验: token = {}", token);
            Map claims = JwtUtil.parseToken(token, JwtProperties.SECRET_KEY);
            //获得负载数据,注意写法
            Integer id = Integer.valueOf(claims.get("id").toString());
            String name = claims.get("name").toString();

            //3、通过,放行
            return true;

        } catch (Exception exception) {

            //4、不通过,响应 401 状态码
            response.setStatus(401);
            throw new Exception("token检验未通过,exception = " + exception);
        }
    }
}

2.将拦截器注册进spring配置中

编写配置类,注册拦截器,并排除不需要的拦截地址

@Configuration
@Slf4j
public class InterceptorConfig implements WebMvcConfigurer {

    @Resource
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")  // 其他接口需要token验证
                //排除knife4j的接口文档页面
                .excludePathPatterns("/**.html")
                .excludePathPatterns("/v3/api-docs/**")
                //排除登录注册页面
                .excludePathPatterns("/login")
                .excludePathPatterns("/register");

    }

}

3.启动项目,验证拦截是否成功

1)请求头中不添加token,访问/health

显示错误页面,这里可以编写全局异常类进行捕获,本次求简,就没写全局异常类。

 2)将访问/login得到的token 加入请求头,再次访问/health

请求成功

自此,token生成和拦截校验结束。

三、拓展:

下面介绍,将jwt配置类解耦出来更好的办法

1.把jwt配置类的属性与application.yml 联系起来。

@Configuration
@ConfigurationProperties(prefix = "jwt")
@Data
public class JwtProperties {

    /**
     * jwt令牌相关配置
     */
    private String secretKey;//签名秘钥
    private int expiretTime;//过期时间
    private String tokenName;//设置前端传递过来的令牌名称
}

2.application.yml 配置

#jwt(token)配置
jwt:
  #签名秘钥
  secretKey: secretKey
  #过期时间(单位 day)
  expiretTime: 7
  #设置前端传递过来的令牌名称
  tokenName: token

3.jwt的util类不变。

4.token拦截校验类需要更改一点


/**
 * jwt令牌的拦截检验(token)
 */
@Component
@Slf4j
public class LoginTokenInterceptor implements HandlerInterceptor {
    @Resource
    private JwtProperties jwtProperties;

    /**
     * 校验jwt(token)
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getTokenName());

        if (StringUtils.isBlank(token)) {
            throw new Exception("未登录");
        }

        String secretKey = jwtProperties.getSecretKey();
        int expiretTime = jwtProperties.getExpiretTime();
        String tokenName = jwtProperties.getTokenName();

        //2、校验令牌
        try {
            log.info("jwt校验: token = {}", token);
            Map claims = JwtUtil.parseToken(token, jwtProperties.getSecretKey());

            Integer id = Integer.valueOf(claims.get("id").toString());

            String account = claims.get("account").toString();

        //3、通过,放行
            return true;

        } catch (Exception exception) {

        //4、不通过,响应 401 状态码
            response.setStatus(401);
            throw new Exception("token检验未通过,exception = " + exception);
        }
    }
}

5.拦截类注册不需要改变

太晚了,明天在写(~_~)。

以上,完成。

Spring Boot,我们可以使用拦截器来验证token拦截器是一种在请求处理之前或之后拦截请求的机制。我们可以在拦截编写代码来验证token,并在需要时拒绝请求。为了实现这个目标,我们需要编写一个自定义的拦截器类,并将其配置Spring Boot应用程序。 具体步骤如下: 1. 创建一个自定义的拦截器类,例如TokenInterceptor.java。 2. 在拦截器类编写代码来验证token。可以使用第三方库,例如JWT,来验证token。 3. 创建一个拦截配置类,例如InterceptorConfig.java。 4. 在拦截配置注册自定义拦截器,并配置拦截器的拦截路径和排除路径。 5. 在Spring Boot应用程序启用拦截配置。 下面是一个简单的示例代码,演示如何在Spring Boot使用拦截验证tokenTokenInterceptor.java: ``` public class TokenInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 验证token的代码 // 如果token验证失败,可以使用response对象返回错误信息 return true; } } ``` InterceptorConfig.java: ``` @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Autowired private TokenInterceptor tokenInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor) .addPathPatterns("/**") // 拦截所有请求 .excludePathPatterns("/login"); // 排除登录请求 } } ``` 在上面的示例代码,我们创建了一个名为TokenInterceptor的自定义拦截器类,并实现了HandlerInterceptor接口。在preHandle方法,我们可以编写代码来验证token。如果token验证失败,可以使用response对象返回错误信息。 然后,我们创建了一个名为InterceptorConfig的拦截配置类,并实现了WebMvcConfigurer接口。在addInterceptors方法,我们注册了TokenInterceptor拦截器,并配置拦截路径和排除路径。在这个例子,我们拦截了所有请求,但排除了/login请求。 最后,在Spring Boot应用程序启用拦截配置。这可以通过在应用程序类上添加@EnableWebMvc注解来实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值