Java生成Token并添加拦截器校验Token,实现判断用户是否登录

添加JWT依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

添加工具类,包含

  • 生成Token方法
  • 从token中获取userId
  • 从token中获取userName
  • 查看Token是否过期
package com.szx.exam.util;

import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;

/**
 * @author songzx
 * @create 2023-06-25 13:55
 */
public class JwtHelper {
    
    
    // 随机字符串混淆Token
    private static final String tokenSignKey = "uNvs^pML-E";

    /**
     * 生成Token,并保存userID和userName信息
     * @param userId
     * @param userName
     * @return
     */
    public static String createToken(Long userId, String userName) {
    
    
        long tokenExpiration = 1000L * 60 * 60 * 24 * 30; // 过期时间,设置30天
        String token = Jwts.builder()
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .claim("userId", userId)
                .claim("userName", userName)
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }

    /**
     * 从token中获取userID
     * @param token
     * @return
     */
    public static Long getUserId(String token) {
    
    
        if (StringUtils.isEmpty(token)) return null;
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        Integer userId = (Integer) claims.get("userId");
        return userId.longValue();
    }

    /**
     * 从token中获取用户姓名
     * @param token
     * @return
     */
    public static String getUserName(String token) {
    
    
        if (StringUtils.isEmpty(token)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return (String) claims.get("userName");
    }

    /**
     * 查看Token是否过期
     * @param token
     * @return false 未过期,true 已过期
     */
    public static Boolean tokenExpired(String token) {
    
    
        try {
    
    
            Claims claims = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
            Date expiration = claims.getExpiration();
            Date currentDate = new Date();
            return expiration.before(currentDate);
        } catch (ExpiredJwtException ex) {
    
    
            return true;
        } catch (Exception ex) {
    
    
            return true;
        }
    }
}

添加 handle

package com.szx.exam.handle;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.szx.exam.exception.SsyxException;
import com.szx.exam.util.JwtHelper;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author songzx
 * @create 2022-10-12 9:48
 */
public class TokenHandle implements HandlerInterceptor {
    
    

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        if(!(handler instanceof HandlerMethod)){
    
    
            return true;
        }
        // 从请求头中获取token
        String token = request.getHeader("X-Token");
        // 校验token
        if(StringUtils.isEmpty(token) || JwtHelper.tokenExpired(token)){
    
    
            throw new SsyxException("登录过期,请重新登录",401);
        }
        return true;
    }
}

添加 TokenConfig,设置需要过滤的接口信息,不在过滤中的接口都将配拦截校验是否存在token

@Configuration
public class TokenConfig implements WebMvcConfigurer {
    
    

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        registry.addInterceptor(new TokenHandle())
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/stu/register",
                        "/stu/login",
                        "/swagger-ui.html",
                        "/webjars/**",
                        "/swagger-resources/**"
                );
    }
}

测试

有如下接口:

http://localhost:9000/exam/saveExam

image-20230625153900273

在不加Token的情况下,或者Token已经过期的情况下, 发起请求,返回401

image-20230625154226048

现在生成一个Token,

image-20230625154504196

将得到的Token加在请求头中,再次发起请求

image-20230625154435476

可以看到本次请求正常返回200

补充:
如果项目中使用了Swagger,则在swagger中请求接口时也会被拦截器拦截,出现401提示,我们可以在swagger的配置类中添加请求头

package com.szx.exam.config;

import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.List;


/**
 * Swagger2配置信息
 */
@Configuration
@EnableSwagger2
public class Swagger2Config {
    
    

    @Bean
    public Docket webApiConfig(){
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("webApi")
                .apiInfo(webApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.szx.exam"))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build();
    }

    public ApiInfo webApiInfo(){
    
    
        return new ApiInfoBuilder()
                .title("Api文档")
                .description("文本档描述了定义的接口")
                .version("1.0")
                .contact(new Contact("szx", "https://blog.csdn.net/SongZhengxing_?spm=1010.2135.3001.5343","[email protected]"))
                .build();
    }

    @Bean
    public Docket docket() {
    
    
        // 设置请求头
        List<Parameter> parameters = new ArrayList<>();
        parameters.add(new ParameterBuilder()
                .name("X-Token") // 字段名
                .description("添加请求头信息,校验是否登录") // 描述
                .modelRef(new ModelRef("string")) // 数据类型
                .parameterType("header") // 参数类型
                .defaultValue("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWSq0oULIyNLM0MDEyMTc01FEqLU4t8kvMTVWyUno2t-_p7NlGSrUA1d5cpicAAAA.i6QU9I5h0hKHupiAK3JEfribAbQKRIXAYM4qUWR0PFGJenJUXz50aMMuxenUUBCsPI9-79m9JjB3SQLKc8xEOw") // 默认值:可自己设置
                .hidden(true) // 是否隐藏
                .required(false) // 是否必须
                .build());

        // 创建一个 swagger 的 bean 实例
        return new Docket(DocumentationType.SWAGGER_2)
                // 配置接口信息
                .select() // 设置扫描接口
                // 配置如何扫描接口
                .apis(RequestHandlerSelectors
                        .basePackage("com.szx.exam") // 扫描指定包下的接口,最为常用
                )
                .paths(PathSelectors
                        .any() // 满足条件的路径,该断言总为true
                )
                .build()
                .globalOperationParameters(parameters);
    }

}

猜你喜欢

转载自blog.csdn.net/SongZhengxing_/article/details/131379687